Improve max_insns_skipped logic
[official-gcc.git] / gcc / ada / exp_prag.adb
blob7ed11362fd59b1a303fd02fa5db9e7a35d37f445
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-2017, 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_Ch8; use Sem_Ch8;
46 with Sem_Util; use Sem_Util;
47 with Sinfo; use Sinfo;
48 with Sinput; use Sinput;
49 with Snames; use Snames;
50 with Stringt; use Stringt;
51 with Stand; use Stand;
52 with Tbuild; use Tbuild;
53 with Uintp; use Uintp;
54 with Validsw; use Validsw;
56 package body Exp_Prag is
58 -----------------------
59 -- Local Subprograms --
60 -----------------------
62 function Arg1 (N : Node_Id) return Node_Id;
63 function Arg2 (N : Node_Id) return Node_Id;
64 function Arg3 (N : Node_Id) return Node_Id;
65 -- Obtain specified pragma argument expression
67 procedure Expand_Pragma_Abort_Defer (N : Node_Id);
68 procedure Expand_Pragma_Check (N : Node_Id);
69 procedure Expand_Pragma_Common_Object (N : Node_Id);
70 procedure Expand_Pragma_Import_Or_Interface (N : Node_Id);
71 procedure Expand_Pragma_Inspection_Point (N : Node_Id);
72 procedure Expand_Pragma_Interrupt_Priority (N : Node_Id);
73 procedure Expand_Pragma_Loop_Variant (N : Node_Id);
74 procedure Expand_Pragma_Psect_Object (N : Node_Id);
75 procedure Expand_Pragma_Relative_Deadline (N : Node_Id);
76 procedure Expand_Pragma_Suppress_Initialization (N : Node_Id);
78 procedure Undo_Initialization (Def_Id : Entity_Id; N : Node_Id);
79 -- This procedure is used to undo initialization already done for Def_Id,
80 -- which is always an E_Variable, in response to the occurrence of the
81 -- pragma N, a pragma Interface, Import, or Suppress_Initialization. In all
82 -- these cases we want no initialization to occur, but we have already done
83 -- the initialization by the time we see the pragma, so we have to undo it.
85 ----------
86 -- Arg1 --
87 ----------
89 function Arg1 (N : Node_Id) return Node_Id is
90 Arg : constant Node_Id := First (Pragma_Argument_Associations (N));
91 begin
92 if Present (Arg)
93 and then Nkind (Arg) = N_Pragma_Argument_Association
94 then
95 return Expression (Arg);
96 else
97 return Arg;
98 end if;
99 end Arg1;
101 ----------
102 -- Arg2 --
103 ----------
105 function Arg2 (N : Node_Id) return Node_Id is
106 Arg1 : constant Node_Id := First (Pragma_Argument_Associations (N));
108 begin
109 if No (Arg1) then
110 return Empty;
112 else
113 declare
114 Arg : constant Node_Id := Next (Arg1);
115 begin
116 if Present (Arg)
117 and then Nkind (Arg) = N_Pragma_Argument_Association
118 then
119 return Expression (Arg);
120 else
121 return Arg;
122 end if;
123 end;
124 end if;
125 end Arg2;
127 ----------
128 -- Arg3 --
129 ----------
131 function Arg3 (N : Node_Id) return Node_Id is
132 Arg1 : constant Node_Id := First (Pragma_Argument_Associations (N));
134 begin
135 if No (Arg1) then
136 return Empty;
138 else
139 declare
140 Arg : Node_Id := Next (Arg1);
141 begin
142 if No (Arg) then
143 return Empty;
145 else
146 Next (Arg);
148 if Present (Arg)
149 and then Nkind (Arg) = N_Pragma_Argument_Association
150 then
151 return Expression (Arg);
152 else
153 return Arg;
154 end if;
155 end if;
156 end;
157 end if;
158 end Arg3;
160 ---------------------
161 -- Expand_N_Pragma --
162 ---------------------
164 procedure Expand_N_Pragma (N : Node_Id) is
165 Pname : constant Name_Id := Pragma_Name (N);
166 Prag_Id : constant Pragma_Id := Get_Pragma_Id (Pname);
168 begin
169 -- Rewrite pragma ignored by Ignore_Pragma to null statement, so that
170 -- the back end doesn't see it. The same goes for pragma
171 -- Default_Scalar_Storage_Order if the -gnatI switch was given.
173 if Should_Ignore_Pragma_Sem (N)
174 or else (Prag_Id = Pragma_Default_Scalar_Storage_Order
175 and then Ignore_Rep_Clauses)
176 then
177 Rewrite (N, Make_Null_Statement (Sloc (N)));
178 return;
179 end if;
181 case Prag_Id is
183 -- Pragmas requiring special expander action
185 when Pragma_Abort_Defer =>
186 Expand_Pragma_Abort_Defer (N);
188 when Pragma_Check =>
189 Expand_Pragma_Check (N);
191 when Pragma_Common_Object =>
192 Expand_Pragma_Common_Object (N);
194 when Pragma_Import =>
195 Expand_Pragma_Import_Or_Interface (N);
197 when Pragma_Inspection_Point =>
198 Expand_Pragma_Inspection_Point (N);
200 when Pragma_Interface =>
201 Expand_Pragma_Import_Or_Interface (N);
203 when Pragma_Interrupt_Priority =>
204 Expand_Pragma_Interrupt_Priority (N);
206 when Pragma_Loop_Variant =>
207 Expand_Pragma_Loop_Variant (N);
209 when Pragma_Psect_Object =>
210 Expand_Pragma_Psect_Object (N);
212 when Pragma_Relative_Deadline =>
213 Expand_Pragma_Relative_Deadline (N);
215 when Pragma_Suppress_Initialization =>
216 Expand_Pragma_Suppress_Initialization (N);
218 -- All other pragmas need no expander action (includes
219 -- Unknown_Pragma).
221 when others => null;
222 end case;
223 end Expand_N_Pragma;
225 -------------------------------
226 -- Expand_Pragma_Abort_Defer --
227 -------------------------------
229 -- An Abort_Defer pragma appears as the first statement in a handled
230 -- statement sequence (right after the begin). It defers aborts for
231 -- the entire statement sequence, but not for any declarations or
232 -- handlers (if any) associated with this statement sequence.
234 -- The transformation is to transform
236 -- pragma Abort_Defer;
237 -- statements;
239 -- into
241 -- begin
242 -- Abort_Defer.all;
243 -- statements
244 -- exception
245 -- when all others =>
246 -- Abort_Undefer.all;
247 -- raise;
248 -- at end
249 -- Abort_Undefer_Direct;
250 -- end;
252 procedure Expand_Pragma_Abort_Defer (N : Node_Id) is
253 begin
254 -- Abort_Defer has no useful effect if Abort's are not allowed
256 if not Abort_Allowed then
257 return;
258 end if;
260 -- Normal case where abort is possible
262 declare
263 Loc : constant Source_Ptr := Sloc (N);
264 Stm : Node_Id;
265 Stms : List_Id;
266 HSS : Node_Id;
267 Blk : constant Entity_Id :=
268 New_Internal_Entity (E_Block, Current_Scope, Sloc (N), 'B');
269 AUD : constant Entity_Id := RTE (RE_Abort_Undefer_Direct);
271 begin
272 Stms := New_List (Build_Runtime_Call (Loc, RE_Abort_Defer));
273 loop
274 Stm := Remove_Next (N);
275 exit when No (Stm);
276 Append (Stm, Stms);
277 end loop;
279 HSS :=
280 Make_Handled_Sequence_Of_Statements (Loc,
281 Statements => Stms,
282 At_End_Proc => New_Occurrence_Of (AUD, Loc));
284 -- Present the Abort_Undefer_Direct function to the backend so that
285 -- it can inline the call to the function.
287 Add_Inlined_Body (AUD, N);
289 Rewrite (N,
290 Make_Block_Statement (Loc, Handled_Statement_Sequence => HSS));
292 Set_Scope (Blk, Current_Scope);
293 Set_Etype (Blk, Standard_Void_Type);
294 Set_Identifier (N, New_Occurrence_Of (Blk, Sloc (N)));
295 Expand_At_End_Handler (HSS, Blk);
296 Analyze (N);
297 end;
298 end Expand_Pragma_Abort_Defer;
300 --------------------------
301 -- Expand_Pragma_Check --
302 --------------------------
304 procedure Expand_Pragma_Check (N : Node_Id) is
305 Cond : constant Node_Id := Arg2 (N);
306 Nam : constant Name_Id := Chars (Arg1 (N));
307 Msg : Node_Id;
309 Loc : constant Source_Ptr := Sloc (First_Node (Cond));
310 -- Source location used in the case of a failed assertion: point to the
311 -- failing condition, not Loc. Note that the source location of the
312 -- expression is not usually the best choice here, because it points to
313 -- the location of the topmost tree node, which may be an operator in
314 -- the middle of the source text of the expression. For example, it gets
315 -- located on the last AND keyword in a chain of boolean expressiond
316 -- AND'ed together. It is best to put the message on the first character
317 -- of the condition, which is the effect of the First_Node call here.
318 -- This source location is used to build the default exception message,
319 -- and also as the sloc of the call to the runtime subprogram raising
320 -- Assert_Failure, so that coverage analysis tools can relate the
321 -- call to the failed check.
323 begin
324 -- Nothing to do if pragma is ignored
326 if Is_Ignored (N) then
327 return;
328 end if;
330 -- Since this check is active, rewrite the pragma into a corresponding
331 -- if statement, and then analyze the statement.
333 -- The normal case expansion transforms:
335 -- pragma Check (name, condition [,message]);
337 -- into
339 -- if not condition then
340 -- System.Assertions.Raise_Assert_Failure (Str);
341 -- end if;
343 -- where Str is the message if one is present, or the default of
344 -- name failed at file:line if no message is given (the "name failed
345 -- at" is omitted for name = Assertion, since it is redundant, given
346 -- that the name of the exception is Assert_Failure.)
348 -- Also, instead of "XXX failed at", we generate slightly
349 -- different messages for some of the contract assertions (see
350 -- code below for details).
352 -- An alternative expansion is used when the No_Exception_Propagation
353 -- restriction is active and there is a local Assert_Failure handler.
354 -- This is not a common combination of circumstances, but it occurs in
355 -- the context of Aunit and the zero footprint profile. In this case we
356 -- generate:
358 -- if not condition then
359 -- raise Assert_Failure;
360 -- end if;
362 -- This will then be transformed into a goto, and the local handler will
363 -- be able to handle the assert error (which would not be the case if a
364 -- call is made to the Raise_Assert_Failure procedure).
366 -- We also generate the direct raise if the Suppress_Exception_Locations
367 -- is active, since we don't want to generate messages in this case.
369 -- Note that the reason we do not always generate a direct raise is that
370 -- the form in which the procedure is called allows for more efficient
371 -- breakpointing of assertion errors.
373 -- Generate the appropriate if statement. Note that we consider this to
374 -- be an explicit conditional in the source, not an implicit if, so we
375 -- do not call Make_Implicit_If_Statement.
377 -- Case where we generate a direct raise
379 if ((Debug_Flag_Dot_G
380 or else Restriction_Active (No_Exception_Propagation))
381 and then Present (Find_Local_Handler (RTE (RE_Assert_Failure), N)))
382 or else (Opt.Exception_Locations_Suppressed and then No (Arg3 (N)))
383 then
384 Rewrite (N,
385 Make_If_Statement (Loc,
386 Condition => Make_Op_Not (Loc, Right_Opnd => Cond),
387 Then_Statements => New_List (
388 Make_Raise_Statement (Loc,
389 Name => New_Occurrence_Of (RTE (RE_Assert_Failure), Loc)))));
391 -- Case where we call the procedure
393 else
394 -- If we have a message given, use it
396 if Present (Arg3 (N)) then
397 Msg := Get_Pragma_Arg (Arg3 (N));
399 -- Here we have no string, so prepare one
401 else
402 declare
403 Loc_Str : constant String := Build_Location_String (Loc);
405 begin
406 Name_Len := 0;
408 -- For Assert, we just use the location
410 if Nam = Name_Assert then
411 null;
413 -- For predicate, we generate the string "predicate failed at
414 -- yyy". We prefer all lower case for predicate.
416 elsif Nam = Name_Predicate then
417 Add_Str_To_Name_Buffer ("predicate failed at ");
419 -- For special case of Precondition/Postcondition the string is
420 -- "failed xx from yy" where xx is precondition/postcondition
421 -- in all lower case. The reason for this different wording is
422 -- that the failure is not at the point of occurrence of the
423 -- pragma, unlike the other Check cases.
425 elsif Nam_In (Nam, Name_Precondition, Name_Postcondition) then
426 Get_Name_String (Nam);
427 Insert_Str_In_Name_Buffer ("failed ", 1);
428 Add_Str_To_Name_Buffer (" from ");
430 -- For special case of Invariant, the string is "failed
431 -- invariant from yy", to be consistent with the string that is
432 -- generated for the aspect case (the code later on checks for
433 -- this specific string to modify it in some cases, so this is
434 -- functionally important).
436 elsif Nam = Name_Invariant then
437 Add_Str_To_Name_Buffer ("failed invariant from ");
439 -- For all other checks, the string is "xxx failed at yyy"
440 -- where xxx is the check name with appropriate casing.
442 else
443 Get_Name_String (Nam);
444 Set_Casing
445 (Identifier_Casing (Source_Index (Current_Sem_Unit)));
446 Add_Str_To_Name_Buffer (" failed at ");
447 end if;
449 -- In all cases, add location string
451 Add_Str_To_Name_Buffer (Loc_Str);
453 -- Build the message
455 Msg := Make_String_Literal (Loc, Name_Buffer (1 .. Name_Len));
456 end;
457 end if;
459 -- Now rewrite as an if statement
461 Rewrite (N,
462 Make_If_Statement (Loc,
463 Condition => Make_Op_Not (Loc, Right_Opnd => Cond),
464 Then_Statements => New_List (
465 Make_Procedure_Call_Statement (Loc,
466 Name =>
467 New_Occurrence_Of (RTE (RE_Raise_Assert_Failure), Loc),
468 Parameter_Associations => New_List (Relocate_Node (Msg))))));
469 end if;
471 Analyze (N);
473 -- If new condition is always false, give a warning
475 if Warn_On_Assertion_Failure
476 and then Nkind (N) = N_Procedure_Call_Statement
477 and then Is_RTE (Entity (Name (N)), RE_Raise_Assert_Failure)
478 then
479 -- If original condition was a Standard.False, we assume that this is
480 -- indeed intended to raise assert error and no warning is required.
482 if Is_Entity_Name (Original_Node (Cond))
483 and then Entity (Original_Node (Cond)) = Standard_False
484 then
485 null;
487 elsif Nam = Name_Assert then
488 Error_Msg_N ("?A?assertion will fail at run time", N);
489 else
490 Error_Msg_N ("?A?check will fail at run time", N);
491 end if;
492 end if;
493 end Expand_Pragma_Check;
495 ---------------------------------
496 -- Expand_Pragma_Common_Object --
497 ---------------------------------
499 -- Use a machine attribute to replicate semantic effect in DEC Ada
501 -- pragma Machine_Attribute (intern_name, "common_object", extern_name);
503 -- For now we do nothing with the size attribute ???
505 -- Note: Psect_Object shares this processing
507 procedure Expand_Pragma_Common_Object (N : Node_Id) is
508 Loc : constant Source_Ptr := Sloc (N);
510 Internal : constant Node_Id := Arg1 (N);
511 External : constant Node_Id := Arg2 (N);
513 Psect : Node_Id;
514 -- Psect value upper cased as string literal
516 Iloc : constant Source_Ptr := Sloc (Internal);
517 Eloc : constant Source_Ptr := Sloc (External);
518 Ploc : Source_Ptr;
520 begin
521 -- Acquire Psect value and fold to upper case
523 if Present (External) then
524 if Nkind (External) = N_String_Literal then
525 String_To_Name_Buffer (Strval (External));
526 else
527 Get_Name_String (Chars (External));
528 end if;
530 Set_All_Upper_Case;
532 Psect :=
533 Make_String_Literal (Eloc, Strval => String_From_Name_Buffer);
535 else
536 Get_Name_String (Chars (Internal));
537 Set_All_Upper_Case;
538 Psect :=
539 Make_String_Literal (Iloc, Strval => String_From_Name_Buffer);
540 end if;
542 Ploc := Sloc (Psect);
544 -- Insert the pragma
546 Insert_After_And_Analyze (N,
547 Make_Pragma (Loc,
548 Chars => Name_Machine_Attribute,
549 Pragma_Argument_Associations => New_List (
550 Make_Pragma_Argument_Association (Iloc,
551 Expression => New_Copy_Tree (Internal)),
552 Make_Pragma_Argument_Association (Eloc,
553 Expression =>
554 Make_String_Literal (Sloc => Ploc, Strval => "common_object")),
555 Make_Pragma_Argument_Association (Ploc,
556 Expression => New_Copy_Tree (Psect)))));
557 end Expand_Pragma_Common_Object;
559 ----------------------------------
560 -- Expand_Pragma_Contract_Cases --
561 ----------------------------------
563 -- Pragma Contract_Cases is expanded in the following manner:
565 -- subprogram S is
566 -- Count : Natural := 0;
567 -- Flag_1 : Boolean := False;
568 -- . . .
569 -- Flag_N : Boolean := False;
570 -- Flag_N+1 : Boolean := False; -- when "others" present
571 -- Pref_1 : ...;
572 -- . . .
573 -- Pref_M : ...;
575 -- <preconditions (if any)>
577 -- -- Evaluate all case guards
579 -- if Case_Guard_1 then
580 -- Flag_1 := True;
581 -- Count := Count + 1;
582 -- end if;
583 -- . . .
584 -- if Case_Guard_N then
585 -- Flag_N := True;
586 -- Count := Count + 1;
587 -- end if;
589 -- -- Emit errors depending on the number of case guards that
590 -- -- evaluated to True.
592 -- if Count = 0 then
593 -- raise Assertion_Error with "xxx contract cases incomplete";
594 -- <or>
595 -- Flag_N+1 := True; -- when "others" present
597 -- elsif Count > 1 then
598 -- declare
599 -- Str0 : constant String :=
600 -- "contract cases overlap for subprogram ABC";
601 -- Str1 : constant String :=
602 -- (if Flag_1 then
603 -- Str0 & "case guard at xxx evaluates to True"
604 -- else Str0);
605 -- StrN : constant String :=
606 -- (if Flag_N then
607 -- StrN-1 & "case guard at xxx evaluates to True"
608 -- else StrN-1);
609 -- begin
610 -- raise Assertion_Error with StrN;
611 -- end;
612 -- end if;
614 -- -- Evaluate all attribute 'Old prefixes found in the selected
615 -- -- consequence.
617 -- if Flag_1 then
618 -- Pref_1 := <prefix of 'Old found in Consequence_1>
619 -- . . .
620 -- elsif Flag_N then
621 -- Pref_M := <prefix of 'Old found in Consequence_N>
622 -- end if;
624 -- procedure _Postconditions is
625 -- begin
626 -- <postconditions (if any)>
628 -- if Flag_1 and then not Consequence_1 then
629 -- raise Assertion_Error with "failed contract case at xxx";
630 -- end if;
631 -- . . .
632 -- if Flag_N[+1] and then not Consequence_N[+1] then
633 -- raise Assertion_Error with "failed contract case at xxx";
634 -- end if;
635 -- end _Postconditions;
636 -- begin
637 -- . . .
638 -- end S;
640 procedure Expand_Pragma_Contract_Cases
641 (CCs : Node_Id;
642 Subp_Id : Entity_Id;
643 Decls : List_Id;
644 Stmts : in out List_Id)
646 Loc : constant Source_Ptr := Sloc (CCs);
648 procedure Case_Guard_Error
649 (Decls : List_Id;
650 Flag : Entity_Id;
651 Error_Loc : Source_Ptr;
652 Msg : in out Entity_Id);
653 -- Given a declarative list Decls, status flag Flag, the location of the
654 -- error and a string Msg, construct the following check:
655 -- Msg : constant String :=
656 -- (if Flag then
657 -- Msg & "case guard at Error_Loc evaluates to True"
658 -- else Msg);
659 -- The resulting code is added to Decls
661 procedure Consequence_Error
662 (Checks : in out Node_Id;
663 Flag : Entity_Id;
664 Conseq : Node_Id);
665 -- Given an if statement Checks, status flag Flag and a consequence
666 -- Conseq, construct the following check:
667 -- [els]if Flag and then not Conseq then
668 -- raise Assertion_Error
669 -- with "failed contract case at Sloc (Conseq)";
670 -- [end if;]
671 -- The resulting code is added to Checks
673 function Declaration_Of (Id : Entity_Id) return Node_Id;
674 -- Given the entity Id of a boolean flag, generate:
675 -- Id : Boolean := False;
677 procedure Expand_Attributes_In_Consequence
678 (Decls : List_Id;
679 Evals : in out Node_Id;
680 Flag : Entity_Id;
681 Conseq : Node_Id);
682 -- Perform specialized expansion of all attribute 'Old references found
683 -- in consequence Conseq such that at runtime only prefixes coming from
684 -- the selected consequence are evaluated. Similarly expand attribute
685 -- 'Result references by replacing them with identifier _result which
686 -- resolves to the sole formal parameter of procedure _Postconditions.
687 -- Any temporaries generated in the process are added to declarations
688 -- Decls. Evals is a complex if statement tasked with the evaluation of
689 -- all prefixes coming from a single selected consequence. Flag is the
690 -- corresponding case guard flag. Conseq is the consequence expression.
692 function Increment (Id : Entity_Id) return Node_Id;
693 -- Given the entity Id of a numerical variable, generate:
694 -- Id := Id + 1;
696 function Set (Id : Entity_Id) return Node_Id;
697 -- Given the entity Id of a boolean variable, generate:
698 -- Id := True;
700 ----------------------
701 -- Case_Guard_Error --
702 ----------------------
704 procedure Case_Guard_Error
705 (Decls : List_Id;
706 Flag : Entity_Id;
707 Error_Loc : Source_Ptr;
708 Msg : in out Entity_Id)
710 New_Line : constant Character := Character'Val (10);
711 New_Msg : constant Entity_Id := Make_Temporary (Loc, 'S');
713 begin
714 Start_String;
715 Store_String_Char (New_Line);
716 Store_String_Chars (" case guard at ");
717 Store_String_Chars (Build_Location_String (Error_Loc));
718 Store_String_Chars (" evaluates to True");
720 -- Generate:
721 -- New_Msg : constant String :=
722 -- (if Flag then
723 -- Msg & "case guard at Error_Loc evaluates to True"
724 -- else Msg);
726 Append_To (Decls,
727 Make_Object_Declaration (Loc,
728 Defining_Identifier => New_Msg,
729 Constant_Present => True,
730 Object_Definition => New_Occurrence_Of (Standard_String, Loc),
731 Expression =>
732 Make_If_Expression (Loc,
733 Expressions => New_List (
734 New_Occurrence_Of (Flag, Loc),
736 Make_Op_Concat (Loc,
737 Left_Opnd => New_Occurrence_Of (Msg, Loc),
738 Right_Opnd => Make_String_Literal (Loc, End_String)),
740 New_Occurrence_Of (Msg, Loc)))));
742 Msg := New_Msg;
743 end Case_Guard_Error;
745 -----------------------
746 -- Consequence_Error --
747 -----------------------
749 procedure Consequence_Error
750 (Checks : in out Node_Id;
751 Flag : Entity_Id;
752 Conseq : Node_Id)
754 Cond : Node_Id;
755 Error : Node_Id;
757 begin
758 -- Generate:
759 -- Flag and then not Conseq
761 Cond :=
762 Make_And_Then (Loc,
763 Left_Opnd => New_Occurrence_Of (Flag, Loc),
764 Right_Opnd =>
765 Make_Op_Not (Loc,
766 Right_Opnd => Relocate_Node (Conseq)));
768 -- Generate:
769 -- raise Assertion_Error
770 -- with "failed contract case at Sloc (Conseq)";
772 Start_String;
773 Store_String_Chars ("failed contract case at ");
774 Store_String_Chars (Build_Location_String (Sloc (Conseq)));
776 Error :=
777 Make_Procedure_Call_Statement (Loc,
778 Name =>
779 New_Occurrence_Of (RTE (RE_Raise_Assert_Failure), Loc),
780 Parameter_Associations => New_List (
781 Make_String_Literal (Loc, End_String)));
783 if No (Checks) then
784 Checks :=
785 Make_Implicit_If_Statement (CCs,
786 Condition => Cond,
787 Then_Statements => New_List (Error));
789 else
790 if No (Elsif_Parts (Checks)) then
791 Set_Elsif_Parts (Checks, New_List);
792 end if;
794 Append_To (Elsif_Parts (Checks),
795 Make_Elsif_Part (Loc,
796 Condition => Cond,
797 Then_Statements => New_List (Error)));
798 end if;
799 end Consequence_Error;
801 --------------------
802 -- Declaration_Of --
803 --------------------
805 function Declaration_Of (Id : Entity_Id) return Node_Id is
806 begin
807 return
808 Make_Object_Declaration (Loc,
809 Defining_Identifier => Id,
810 Object_Definition => New_Occurrence_Of (Standard_Boolean, Loc),
811 Expression => New_Occurrence_Of (Standard_False, Loc));
812 end Declaration_Of;
814 --------------------------------------
815 -- Expand_Attributes_In_Consequence --
816 --------------------------------------
818 procedure Expand_Attributes_In_Consequence
819 (Decls : List_Id;
820 Evals : in out Node_Id;
821 Flag : Entity_Id;
822 Conseq : Node_Id)
824 Eval_Stmts : List_Id := No_List;
825 -- The evaluation sequence expressed as assignment statements of all
826 -- prefixes of attribute 'Old found in the current consequence.
828 function Expand_Attributes (N : Node_Id) return Traverse_Result;
829 -- Determine whether an arbitrary node denotes attribute 'Old or
830 -- 'Result and if it does, perform all expansion-related actions.
832 -----------------------
833 -- Expand_Attributes --
834 -----------------------
836 function Expand_Attributes (N : Node_Id) return Traverse_Result is
837 Decl : Node_Id;
838 Pref : Node_Id;
839 Temp : Entity_Id;
841 begin
842 -- Attribute 'Old
844 if Nkind (N) = N_Attribute_Reference
845 and then Attribute_Name (N) = Name_Old
846 then
847 Pref := Prefix (N);
848 Temp := Make_Temporary (Loc, 'T', Pref);
849 Set_Etype (Temp, Etype (Pref));
851 -- Generate a temporary to capture the value of the prefix:
852 -- Temp : <Pref type>;
854 Decl :=
855 Make_Object_Declaration (Loc,
856 Defining_Identifier => Temp,
857 Object_Definition =>
858 New_Occurrence_Of (Etype (Pref), Loc));
860 -- Place that temporary at the beginning of declarations, to
861 -- prevent anomalies in the GNATprove flow-analysis pass in
862 -- the precondition procedure that follows.
864 Prepend_To (Decls, Decl);
866 -- If the type is unconstrained, the prefix provides its
867 -- value and constraint, so add it to declaration.
869 if not Is_Constrained (Etype (Pref))
870 and then Is_Entity_Name (Pref)
871 then
872 Set_Expression (Decl, Pref);
873 Analyze (Decl);
875 -- Otherwise add an assignment statement to temporary using
876 -- prefix as RHS.
878 else
879 Analyze (Decl);
881 if No (Eval_Stmts) then
882 Eval_Stmts := New_List;
883 end if;
885 Append_To (Eval_Stmts,
886 Make_Assignment_Statement (Loc,
887 Name => New_Occurrence_Of (Temp, Loc),
888 Expression => Pref));
890 end if;
892 -- Ensure that the prefix is valid
894 if Validity_Checks_On and then Validity_Check_Operands then
895 Ensure_Valid (Pref);
896 end if;
898 -- Replace the original attribute 'Old by a reference to the
899 -- generated temporary.
901 Rewrite (N, New_Occurrence_Of (Temp, Loc));
903 -- Attribute 'Result
905 elsif Is_Attribute_Result (N) then
906 Rewrite (N, Make_Identifier (Loc, Name_uResult));
907 end if;
909 return OK;
910 end Expand_Attributes;
912 procedure Expand_Attributes_In is
913 new Traverse_Proc (Expand_Attributes);
915 -- Start of processing for Expand_Attributes_In_Consequence
917 begin
918 -- Inspect the consequence and expand any attribute 'Old and 'Result
919 -- references found within.
921 Expand_Attributes_In (Conseq);
923 -- The consequence does not contain any attribute 'Old references
925 if No (Eval_Stmts) then
926 return;
927 end if;
929 -- Augment the machinery to trigger the evaluation of all prefixes
930 -- found in the step above. If Eval is empty, then this is the first
931 -- consequence to yield expansion of 'Old. Generate:
933 -- if Flag then
934 -- <evaluation statements>
935 -- end if;
937 if No (Evals) then
938 Evals :=
939 Make_Implicit_If_Statement (CCs,
940 Condition => New_Occurrence_Of (Flag, Loc),
941 Then_Statements => Eval_Stmts);
943 -- Otherwise generate:
944 -- elsif Flag then
945 -- <evaluation statements>
946 -- end if;
948 else
949 if No (Elsif_Parts (Evals)) then
950 Set_Elsif_Parts (Evals, New_List);
951 end if;
953 Append_To (Elsif_Parts (Evals),
954 Make_Elsif_Part (Loc,
955 Condition => New_Occurrence_Of (Flag, Loc),
956 Then_Statements => Eval_Stmts));
957 end if;
958 end Expand_Attributes_In_Consequence;
960 ---------------
961 -- Increment --
962 ---------------
964 function Increment (Id : Entity_Id) return Node_Id is
965 begin
966 return
967 Make_Assignment_Statement (Loc,
968 Name => New_Occurrence_Of (Id, Loc),
969 Expression =>
970 Make_Op_Add (Loc,
971 Left_Opnd => New_Occurrence_Of (Id, Loc),
972 Right_Opnd => Make_Integer_Literal (Loc, 1)));
973 end Increment;
975 ---------
976 -- Set --
977 ---------
979 function Set (Id : Entity_Id) return Node_Id is
980 begin
981 return
982 Make_Assignment_Statement (Loc,
983 Name => New_Occurrence_Of (Id, Loc),
984 Expression => New_Occurrence_Of (Standard_True, Loc));
985 end Set;
987 -- Local variables
989 Aggr : constant Node_Id :=
990 Expression (First (Pragma_Argument_Associations (CCs)));
992 Case_Guard : Node_Id;
993 CG_Checks : Node_Id;
994 CG_Stmts : List_Id;
995 Conseq : Node_Id;
996 Conseq_Checks : Node_Id := Empty;
997 Count : Entity_Id;
998 Count_Decl : Node_Id;
999 Error_Decls : List_Id;
1000 Flag : Entity_Id;
1001 Flag_Decl : Node_Id;
1002 If_Stmt : Node_Id;
1003 Msg_Str : Entity_Id := Empty;
1004 Multiple_PCs : Boolean;
1005 Old_Evals : Node_Id := Empty;
1006 Others_Decl : Node_Id;
1007 Others_Flag : Entity_Id := Empty;
1008 Post_Case : Node_Id;
1010 -- Start of processing for Expand_Pragma_Contract_Cases
1012 begin
1013 -- Do nothing if pragma is not enabled. If pragma is disabled, it has
1014 -- already been rewritten as a Null statement.
1016 if Is_Ignored (CCs) then
1017 return;
1019 -- Guard against malformed contract cases
1021 elsif Nkind (Aggr) /= N_Aggregate then
1022 return;
1023 end if;
1025 -- The expansion of contract cases is quite distributed as it produces
1026 -- various statements to evaluate the case guards and consequences. To
1027 -- preserve the original context, set the Is_Assertion_Expr flag. This
1028 -- aids the Ghost legality checks when verifying the placement of a
1029 -- reference to a Ghost entity.
1031 In_Assertion_Expr := In_Assertion_Expr + 1;
1033 Multiple_PCs := List_Length (Component_Associations (Aggr)) > 1;
1035 -- Create the counter which tracks the number of case guards that
1036 -- evaluate to True.
1038 -- Count : Natural := 0;
1040 Count := Make_Temporary (Loc, 'C');
1041 Count_Decl :=
1042 Make_Object_Declaration (Loc,
1043 Defining_Identifier => Count,
1044 Object_Definition => New_Occurrence_Of (Standard_Natural, Loc),
1045 Expression => Make_Integer_Literal (Loc, 0));
1047 Prepend_To (Decls, Count_Decl);
1048 Analyze (Count_Decl);
1050 -- Create the base error message for multiple overlapping case guards
1052 -- Msg_Str : constant String :=
1053 -- "contract cases overlap for subprogram Subp_Id";
1055 if Multiple_PCs then
1056 Msg_Str := Make_Temporary (Loc, 'S');
1058 Start_String;
1059 Store_String_Chars ("contract cases overlap for subprogram ");
1060 Store_String_Chars (Get_Name_String (Chars (Subp_Id)));
1062 Error_Decls := New_List (
1063 Make_Object_Declaration (Loc,
1064 Defining_Identifier => Msg_Str,
1065 Constant_Present => True,
1066 Object_Definition => New_Occurrence_Of (Standard_String, Loc),
1067 Expression => Make_String_Literal (Loc, End_String)));
1068 end if;
1070 -- Process individual post cases
1072 Post_Case := First (Component_Associations (Aggr));
1073 while Present (Post_Case) loop
1074 Case_Guard := First (Choices (Post_Case));
1075 Conseq := Expression (Post_Case);
1077 -- The "others" choice requires special processing
1079 if Nkind (Case_Guard) = N_Others_Choice then
1080 Others_Flag := Make_Temporary (Loc, 'F');
1081 Others_Decl := Declaration_Of (Others_Flag);
1083 Prepend_To (Decls, Others_Decl);
1084 Analyze (Others_Decl);
1086 -- Check possible overlap between a case guard and "others"
1088 if Multiple_PCs and Exception_Extra_Info then
1089 Case_Guard_Error
1090 (Decls => Error_Decls,
1091 Flag => Others_Flag,
1092 Error_Loc => Sloc (Case_Guard),
1093 Msg => Msg_Str);
1094 end if;
1096 -- Inspect the consequence and perform special expansion of any
1097 -- attribute 'Old and 'Result references found within.
1099 Expand_Attributes_In_Consequence
1100 (Decls => Decls,
1101 Evals => Old_Evals,
1102 Flag => Others_Flag,
1103 Conseq => Conseq);
1105 -- Check the corresponding consequence of "others"
1107 Consequence_Error
1108 (Checks => Conseq_Checks,
1109 Flag => Others_Flag,
1110 Conseq => Conseq);
1112 -- Regular post case
1114 else
1115 -- Create the flag which tracks the state of its associated case
1116 -- guard.
1118 Flag := Make_Temporary (Loc, 'F');
1119 Flag_Decl := Declaration_Of (Flag);
1121 Prepend_To (Decls, Flag_Decl);
1122 Analyze (Flag_Decl);
1124 -- The flag is set when the case guard is evaluated to True
1125 -- if Case_Guard then
1126 -- Flag := True;
1127 -- Count := Count + 1;
1128 -- end if;
1130 If_Stmt :=
1131 Make_Implicit_If_Statement (CCs,
1132 Condition => Relocate_Node (Case_Guard),
1133 Then_Statements => New_List (
1134 Set (Flag),
1135 Increment (Count)));
1137 Append_To (Decls, If_Stmt);
1138 Analyze (If_Stmt);
1140 -- Check whether this case guard overlaps with another one
1142 if Multiple_PCs and Exception_Extra_Info then
1143 Case_Guard_Error
1144 (Decls => Error_Decls,
1145 Flag => Flag,
1146 Error_Loc => Sloc (Case_Guard),
1147 Msg => Msg_Str);
1148 end if;
1150 -- Inspect the consequence and perform special expansion of any
1151 -- attribute 'Old and 'Result references found within.
1153 Expand_Attributes_In_Consequence
1154 (Decls => Decls,
1155 Evals => Old_Evals,
1156 Flag => Flag,
1157 Conseq => Conseq);
1159 -- The corresponding consequence of the case guard which evaluated
1160 -- to True must hold on exit from the subprogram.
1162 Consequence_Error
1163 (Checks => Conseq_Checks,
1164 Flag => Flag,
1165 Conseq => Conseq);
1166 end if;
1168 Next (Post_Case);
1169 end loop;
1171 -- Raise Assertion_Error when none of the case guards evaluate to True.
1172 -- The only exception is when we have "others", in which case there is
1173 -- no error because "others" acts as a default True.
1175 -- Generate:
1176 -- Flag := True;
1178 if Present (Others_Flag) then
1179 CG_Stmts := New_List (Set (Others_Flag));
1181 -- Generate:
1182 -- raise Assertion_Error with "xxx contract cases incomplete";
1184 else
1185 Start_String;
1186 Store_String_Chars (Build_Location_String (Loc));
1187 Store_String_Chars (" contract cases incomplete");
1189 CG_Stmts := New_List (
1190 Make_Procedure_Call_Statement (Loc,
1191 Name =>
1192 New_Occurrence_Of (RTE (RE_Raise_Assert_Failure), Loc),
1193 Parameter_Associations => New_List (
1194 Make_String_Literal (Loc, End_String))));
1195 end if;
1197 CG_Checks :=
1198 Make_Implicit_If_Statement (CCs,
1199 Condition =>
1200 Make_Op_Eq (Loc,
1201 Left_Opnd => New_Occurrence_Of (Count, Loc),
1202 Right_Opnd => Make_Integer_Literal (Loc, 0)),
1203 Then_Statements => CG_Stmts);
1205 -- Detect a possible failure due to several case guards evaluating to
1206 -- True.
1208 -- Generate:
1209 -- elsif Count > 0 then
1210 -- declare
1211 -- <Error_Decls>
1212 -- begin
1213 -- raise Assertion_Error with <Msg_Str>;
1214 -- end if;
1216 if Multiple_PCs then
1217 Set_Elsif_Parts (CG_Checks, New_List (
1218 Make_Elsif_Part (Loc,
1219 Condition =>
1220 Make_Op_Gt (Loc,
1221 Left_Opnd => New_Occurrence_Of (Count, Loc),
1222 Right_Opnd => Make_Integer_Literal (Loc, 1)),
1224 Then_Statements => New_List (
1225 Make_Block_Statement (Loc,
1226 Declarations => Error_Decls,
1227 Handled_Statement_Sequence =>
1228 Make_Handled_Sequence_Of_Statements (Loc,
1229 Statements => New_List (
1230 Make_Procedure_Call_Statement (Loc,
1231 Name =>
1232 New_Occurrence_Of
1233 (RTE (RE_Raise_Assert_Failure), Loc),
1234 Parameter_Associations => New_List (
1235 New_Occurrence_Of (Msg_Str, Loc))))))))));
1236 end if;
1238 Append_To (Decls, CG_Checks);
1239 Analyze (CG_Checks);
1241 -- Once all case guards are evaluated and checked, evaluate any prefixes
1242 -- of attribute 'Old founds in the selected consequence.
1244 if Present (Old_Evals) then
1245 Append_To (Decls, Old_Evals);
1246 Analyze (Old_Evals);
1247 end if;
1249 -- Raise Assertion_Error when the corresponding consequence of a case
1250 -- guard that evaluated to True fails.
1252 if No (Stmts) then
1253 Stmts := New_List;
1254 end if;
1256 Append_To (Stmts, Conseq_Checks);
1258 In_Assertion_Expr := In_Assertion_Expr - 1;
1259 end Expand_Pragma_Contract_Cases;
1261 ---------------------------------------
1262 -- Expand_Pragma_Import_Or_Interface --
1263 ---------------------------------------
1265 procedure Expand_Pragma_Import_Or_Interface (N : Node_Id) is
1266 Def_Id : Entity_Id;
1268 begin
1269 -- In Relaxed_RM_Semantics, support old Ada 83 style:
1270 -- pragma Import (Entity, "external name");
1272 if Relaxed_RM_Semantics
1273 and then List_Length (Pragma_Argument_Associations (N)) = 2
1274 and then Pragma_Name (N) = Name_Import
1275 and then Nkind (Arg2 (N)) = N_String_Literal
1276 then
1277 Def_Id := Entity (Arg1 (N));
1278 else
1279 Def_Id := Entity (Arg2 (N));
1280 end if;
1282 -- Variable case (we have to undo any initialization already done)
1284 if Ekind (Def_Id) = E_Variable then
1285 Undo_Initialization (Def_Id, N);
1287 -- Case of exception with convention C++
1289 elsif Ekind (Def_Id) = E_Exception
1290 and then Convention (Def_Id) = Convention_CPP
1291 then
1292 -- Import a C++ convention
1294 declare
1295 Loc : constant Source_Ptr := Sloc (N);
1296 Rtti_Name : constant Node_Id := Arg3 (N);
1297 Dum : constant Entity_Id := Make_Temporary (Loc, 'D');
1298 Exdata : List_Id;
1299 Lang_Char : Node_Id;
1300 Foreign_Data : Node_Id;
1302 begin
1303 Exdata := Component_Associations (Expression (Parent (Def_Id)));
1305 Lang_Char := Next (First (Exdata));
1307 -- Change the one-character language designator to 'C'
1309 Rewrite (Expression (Lang_Char),
1310 Make_Character_Literal (Loc,
1311 Chars => Name_uC,
1312 Char_Literal_Value => UI_From_Int (Character'Pos ('C'))));
1313 Analyze (Expression (Lang_Char));
1315 -- Change the value of Foreign_Data
1317 Foreign_Data := Next (Next (Next (Next (Lang_Char))));
1319 Insert_Actions (Def_Id, New_List (
1320 Make_Object_Declaration (Loc,
1321 Defining_Identifier => Dum,
1322 Object_Definition =>
1323 New_Occurrence_Of (Standard_Character, Loc)),
1325 Make_Pragma (Loc,
1326 Chars => Name_Import,
1327 Pragma_Argument_Associations => New_List (
1328 Make_Pragma_Argument_Association (Loc,
1329 Expression => Make_Identifier (Loc, Name_Ada)),
1331 Make_Pragma_Argument_Association (Loc,
1332 Expression => Make_Identifier (Loc, Chars (Dum))),
1334 Make_Pragma_Argument_Association (Loc,
1335 Chars => Name_External_Name,
1336 Expression => Relocate_Node (Rtti_Name))))));
1338 Rewrite (Expression (Foreign_Data),
1339 Unchecked_Convert_To (Standard_A_Char,
1340 Make_Attribute_Reference (Loc,
1341 Prefix => Make_Identifier (Loc, Chars (Dum)),
1342 Attribute_Name => Name_Address)));
1343 Analyze (Expression (Foreign_Data));
1344 end;
1346 -- No special expansion required for any other case
1348 else
1349 null;
1350 end if;
1351 end Expand_Pragma_Import_Or_Interface;
1353 -------------------------------------
1354 -- Expand_Pragma_Initial_Condition --
1355 -------------------------------------
1357 procedure Expand_Pragma_Initial_Condition (Spec_Or_Body : Node_Id) is
1358 Loc : constant Source_Ptr := Sloc (Spec_Or_Body);
1360 Check : Node_Id;
1361 Expr : Node_Id;
1362 Init_Cond : Node_Id;
1363 List : List_Id;
1364 Pack_Id : Entity_Id;
1366 begin
1367 if Nkind (Spec_Or_Body) = N_Package_Body then
1368 Pack_Id := Corresponding_Spec (Spec_Or_Body);
1370 if Present (Handled_Statement_Sequence (Spec_Or_Body)) then
1371 List := Statements (Handled_Statement_Sequence (Spec_Or_Body));
1373 -- The package body lacks statements, create an empty list
1375 else
1376 List := New_List;
1378 Set_Handled_Statement_Sequence (Spec_Or_Body,
1379 Make_Handled_Sequence_Of_Statements (Loc, Statements => List));
1380 end if;
1382 elsif Nkind (Spec_Or_Body) = N_Package_Declaration then
1383 Pack_Id := Defining_Entity (Spec_Or_Body);
1385 if Present (Visible_Declarations (Specification (Spec_Or_Body))) then
1386 List := Visible_Declarations (Specification (Spec_Or_Body));
1388 -- The package lacks visible declarations, create an empty list
1390 else
1391 List := New_List;
1393 Set_Visible_Declarations (Specification (Spec_Or_Body), List);
1394 end if;
1396 -- This routine should not be used on anything other than packages
1398 else
1399 raise Program_Error;
1400 end if;
1402 Init_Cond := Get_Pragma (Pack_Id, Pragma_Initial_Condition);
1404 -- The caller should check whether the package is subject to pragma
1405 -- Initial_Condition.
1407 pragma Assert (Present (Init_Cond));
1409 Expr :=
1410 Get_Pragma_Arg (First (Pragma_Argument_Associations (Init_Cond)));
1412 -- The assertion expression was found to be illegal, do not generate the
1413 -- runtime check as it will repeat the illegality.
1415 if Error_Posted (Init_Cond) or else Error_Posted (Expr) then
1416 return;
1417 end if;
1419 -- Generate:
1420 -- pragma Check (Initial_Condition, <Expr>);
1422 Check :=
1423 Make_Pragma (Loc,
1424 Chars => Name_Check,
1425 Pragma_Argument_Associations => New_List (
1426 Make_Pragma_Argument_Association (Loc,
1427 Expression => Make_Identifier (Loc, Name_Initial_Condition)),
1428 Make_Pragma_Argument_Association (Loc,
1429 Expression => New_Copy_Tree (Expr))));
1431 Append_To (List, Check);
1432 Analyze (Check);
1433 end Expand_Pragma_Initial_Condition;
1435 ------------------------------------
1436 -- Expand_Pragma_Inspection_Point --
1437 ------------------------------------
1439 -- If no argument is given, then we supply a default argument list that
1440 -- includes all objects declared at the source level in all subprograms
1441 -- that enclose the inspection point pragma.
1443 procedure Expand_Pragma_Inspection_Point (N : Node_Id) is
1444 Loc : constant Source_Ptr := Sloc (N);
1445 A : List_Id;
1446 Assoc : Node_Id;
1447 S : Entity_Id;
1448 E : Entity_Id;
1450 begin
1451 if No (Pragma_Argument_Associations (N)) then
1452 A := New_List;
1453 S := Current_Scope;
1455 while S /= Standard_Standard loop
1456 E := First_Entity (S);
1457 while Present (E) loop
1458 if Comes_From_Source (E)
1459 and then Is_Object (E)
1460 and then not Is_Entry_Formal (E)
1461 and then Ekind (E) /= E_Component
1462 and then Ekind (E) /= E_Discriminant
1463 and then Ekind (E) /= E_Generic_In_Parameter
1464 and then Ekind (E) /= E_Generic_In_Out_Parameter
1465 then
1466 Append_To (A,
1467 Make_Pragma_Argument_Association (Loc,
1468 Expression => New_Occurrence_Of (E, Loc)));
1469 end if;
1471 Next_Entity (E);
1472 end loop;
1474 S := Scope (S);
1475 end loop;
1477 Set_Pragma_Argument_Associations (N, A);
1478 end if;
1480 -- Expand the arguments of the pragma. Expanding an entity reference
1481 -- is a noop, except in a protected operation, where a reference may
1482 -- have to be transformed into a reference to the corresponding prival.
1483 -- Are there other pragmas that may require this ???
1485 Assoc := First (Pragma_Argument_Associations (N));
1486 while Present (Assoc) loop
1487 Expand (Expression (Assoc));
1488 Next (Assoc);
1489 end loop;
1490 end Expand_Pragma_Inspection_Point;
1492 --------------------------------------
1493 -- Expand_Pragma_Interrupt_Priority --
1494 --------------------------------------
1496 -- Supply default argument if none exists (System.Interrupt_Priority'Last)
1498 procedure Expand_Pragma_Interrupt_Priority (N : Node_Id) is
1499 Loc : constant Source_Ptr := Sloc (N);
1500 begin
1501 if No (Pragma_Argument_Associations (N)) then
1502 Set_Pragma_Argument_Associations (N, New_List (
1503 Make_Pragma_Argument_Association (Loc,
1504 Expression =>
1505 Make_Attribute_Reference (Loc,
1506 Prefix =>
1507 New_Occurrence_Of (RTE (RE_Interrupt_Priority), Loc),
1508 Attribute_Name => Name_Last))));
1509 end if;
1510 end Expand_Pragma_Interrupt_Priority;
1512 --------------------------------
1513 -- Expand_Pragma_Loop_Variant --
1514 --------------------------------
1516 -- Pragma Loop_Variant is expanded in the following manner:
1518 -- Original code
1520 -- for | while ... loop
1521 -- <preceding source statements>
1522 -- pragma Loop_Variant
1523 -- (Increases => Incr_Expr,
1524 -- Decreases => Decr_Expr);
1525 -- <succeeding source statements>
1526 -- end loop;
1528 -- Expanded code
1530 -- Curr_1 : <type of Incr_Expr>;
1531 -- Curr_2 : <type of Decr_Expr>;
1532 -- Old_1 : <type of Incr_Expr>;
1533 -- Old_2 : <type of Decr_Expr>;
1534 -- Flag : Boolean := False;
1536 -- for | while ... loop
1537 -- <preceding source statements>
1539 -- if Flag then
1540 -- Old_1 := Curr_1;
1541 -- Old_2 := Curr_2;
1542 -- end if;
1544 -- Curr_1 := <Incr_Expr>;
1545 -- Curr_2 := <Decr_Expr>;
1547 -- if Flag then
1548 -- if Curr_1 /= Old_1 then
1549 -- pragma Check (Loop_Variant, Curr_1 > Old_1);
1550 -- else
1551 -- pragma Check (Loop_Variant, Curr_2 < Old_2);
1552 -- end if;
1553 -- else
1554 -- Flag := True;
1555 -- end if;
1557 -- <succeeding source statements>
1558 -- end loop;
1560 procedure Expand_Pragma_Loop_Variant (N : Node_Id) is
1561 Loc : constant Source_Ptr := Sloc (N);
1562 Last_Var : constant Node_Id :=
1563 Last (Pragma_Argument_Associations (N));
1565 Curr_Assign : List_Id := No_List;
1566 Flag_Id : Entity_Id := Empty;
1567 If_Stmt : Node_Id := Empty;
1568 Old_Assign : List_Id := No_List;
1569 Loop_Scop : Entity_Id;
1570 Loop_Stmt : Node_Id;
1571 Variant : Node_Id;
1573 procedure Process_Variant (Variant : Node_Id; Is_Last : Boolean);
1574 -- Process a single increasing / decreasing termination variant. Flag
1575 -- Is_Last should be set when processing the last variant.
1577 ---------------------
1578 -- Process_Variant --
1579 ---------------------
1581 procedure Process_Variant (Variant : Node_Id; Is_Last : Boolean) is
1582 function Make_Op
1583 (Loc : Source_Ptr;
1584 Curr_Val : Node_Id;
1585 Old_Val : Node_Id) return Node_Id;
1586 -- Generate a comparison between Curr_Val and Old_Val depending on
1587 -- the change mode (Increases / Decreases) of the variant.
1589 -------------
1590 -- Make_Op --
1591 -------------
1593 function Make_Op
1594 (Loc : Source_Ptr;
1595 Curr_Val : Node_Id;
1596 Old_Val : Node_Id) return Node_Id
1598 begin
1599 if Chars (Variant) = Name_Increases then
1600 return Make_Op_Gt (Loc, Curr_Val, Old_Val);
1601 else pragma Assert (Chars (Variant) = Name_Decreases);
1602 return Make_Op_Lt (Loc, Curr_Val, Old_Val);
1603 end if;
1604 end Make_Op;
1606 -- Local variables
1608 Expr : constant Node_Id := Expression (Variant);
1609 Expr_Typ : constant Entity_Id := Etype (Expr);
1610 Loc : constant Source_Ptr := Sloc (Expr);
1611 Loop_Loc : constant Source_Ptr := Sloc (Loop_Stmt);
1612 Curr_Id : Entity_Id;
1613 Old_Id : Entity_Id;
1614 Prag : Node_Id;
1616 -- Start of processing for Process_Variant
1618 begin
1619 -- All temporaries generated in this routine must be inserted before
1620 -- the related loop statement. Ensure that the proper scope is on the
1621 -- stack when analyzing the temporaries. Note that we also use the
1622 -- Sloc of the related loop.
1624 Push_Scope (Scope (Loop_Scop));
1626 -- Step 1: Create the declaration of the flag which controls the
1627 -- behavior of the assertion on the first iteration of the loop.
1629 if No (Flag_Id) then
1631 -- Generate:
1632 -- Flag : Boolean := False;
1634 Flag_Id := Make_Temporary (Loop_Loc, 'F');
1636 Insert_Action (Loop_Stmt,
1637 Make_Object_Declaration (Loop_Loc,
1638 Defining_Identifier => Flag_Id,
1639 Object_Definition =>
1640 New_Occurrence_Of (Standard_Boolean, Loop_Loc),
1641 Expression =>
1642 New_Occurrence_Of (Standard_False, Loop_Loc)));
1644 -- Prevent an unwanted optimization where the Current_Value of
1645 -- the flag eliminates the if statement which stores the variant
1646 -- values coming from the previous iteration.
1648 -- Flag : Boolean := False;
1649 -- loop
1650 -- if Flag then -- condition rewritten to False
1651 -- Old_N := Curr_N; -- and if statement eliminated
1652 -- end if;
1653 -- . . .
1654 -- Flag := True;
1655 -- end loop;
1657 Set_Current_Value (Flag_Id, Empty);
1658 end if;
1660 -- Step 2: Create the temporaries which store the old and current
1661 -- values of the associated expression.
1663 -- Generate:
1664 -- Curr : <type of Expr>;
1666 Curr_Id := Make_Temporary (Loc, 'C');
1668 Insert_Action (Loop_Stmt,
1669 Make_Object_Declaration (Loop_Loc,
1670 Defining_Identifier => Curr_Id,
1671 Object_Definition => New_Occurrence_Of (Expr_Typ, Loop_Loc)));
1673 -- Generate:
1674 -- Old : <type of Expr>;
1676 Old_Id := Make_Temporary (Loc, 'P');
1678 Insert_Action (Loop_Stmt,
1679 Make_Object_Declaration (Loop_Loc,
1680 Defining_Identifier => Old_Id,
1681 Object_Definition => New_Occurrence_Of (Expr_Typ, Loop_Loc)));
1683 -- Restore original scope after all temporaries have been analyzed
1685 Pop_Scope;
1687 -- Step 3: Store value of the expression from the previous iteration
1689 if No (Old_Assign) then
1690 Old_Assign := New_List;
1691 end if;
1693 -- Generate:
1694 -- Old := Curr;
1696 Append_To (Old_Assign,
1697 Make_Assignment_Statement (Loc,
1698 Name => New_Occurrence_Of (Old_Id, Loc),
1699 Expression => New_Occurrence_Of (Curr_Id, Loc)));
1701 -- Step 4: Store the current value of the expression
1703 if No (Curr_Assign) then
1704 Curr_Assign := New_List;
1705 end if;
1707 -- Generate:
1708 -- Curr := <Expr>;
1710 Append_To (Curr_Assign,
1711 Make_Assignment_Statement (Loc,
1712 Name => New_Occurrence_Of (Curr_Id, Loc),
1713 Expression => Relocate_Node (Expr)));
1715 -- Step 5: Create corresponding assertion to verify change of value
1717 -- Generate:
1718 -- pragma Check (Loop_Variant, Curr <|> Old);
1720 Prag :=
1721 Make_Pragma (Loc,
1722 Chars => Name_Check,
1723 Pragma_Argument_Associations => New_List (
1724 Make_Pragma_Argument_Association (Loc,
1725 Expression => Make_Identifier (Loc, Name_Loop_Variant)),
1726 Make_Pragma_Argument_Association (Loc,
1727 Expression =>
1728 Make_Op (Loc,
1729 Curr_Val => New_Occurrence_Of (Curr_Id, Loc),
1730 Old_Val => New_Occurrence_Of (Old_Id, Loc)))));
1732 -- Generate:
1733 -- if Curr /= Old then
1734 -- <Prag>;
1736 if No (If_Stmt) then
1738 -- When there is just one termination variant, do not compare the
1739 -- old and current value for equality, just check the pragma.
1741 if Is_Last then
1742 If_Stmt := Prag;
1743 else
1744 If_Stmt :=
1745 Make_If_Statement (Loc,
1746 Condition =>
1747 Make_Op_Ne (Loc,
1748 Left_Opnd => New_Occurrence_Of (Curr_Id, Loc),
1749 Right_Opnd => New_Occurrence_Of (Old_Id, Loc)),
1750 Then_Statements => New_List (Prag));
1751 end if;
1753 -- Generate:
1754 -- else
1755 -- <Prag>;
1756 -- end if;
1758 elsif Is_Last then
1759 Set_Else_Statements (If_Stmt, New_List (Prag));
1761 -- Generate:
1762 -- elsif Curr /= Old then
1763 -- <Prag>;
1765 else
1766 if Elsif_Parts (If_Stmt) = No_List then
1767 Set_Elsif_Parts (If_Stmt, New_List);
1768 end if;
1770 Append_To (Elsif_Parts (If_Stmt),
1771 Make_Elsif_Part (Loc,
1772 Condition =>
1773 Make_Op_Ne (Loc,
1774 Left_Opnd => New_Occurrence_Of (Curr_Id, Loc),
1775 Right_Opnd => New_Occurrence_Of (Old_Id, Loc)),
1776 Then_Statements => New_List (Prag)));
1777 end if;
1778 end Process_Variant;
1780 -- Start of processing for Expand_Pragma_Loop_Variant
1782 begin
1783 -- If pragma is not enabled, rewrite as Null statement. If pragma is
1784 -- disabled, it has already been rewritten as a Null statement.
1786 if Is_Ignored (N) then
1787 Rewrite (N, Make_Null_Statement (Loc));
1788 Analyze (N);
1789 return;
1790 end if;
1792 -- The expansion of Loop_Variant is quite distributed as it produces
1793 -- various statements to capture and compare the arguments. To preserve
1794 -- the original context, set the Is_Assertion_Expr flag. This aids the
1795 -- Ghost legality checks when verifying the placement of a reference to
1796 -- a Ghost entity.
1798 In_Assertion_Expr := In_Assertion_Expr + 1;
1800 -- Locate the enclosing loop for which this assertion applies. In the
1801 -- case of Ada 2012 array iteration, we might be dealing with nested
1802 -- loops. Only the outermost loop has an identifier.
1804 Loop_Stmt := N;
1805 while Present (Loop_Stmt) loop
1806 if Nkind (Loop_Stmt) = N_Loop_Statement
1807 and then Present (Identifier (Loop_Stmt))
1808 then
1809 exit;
1810 end if;
1812 Loop_Stmt := Parent (Loop_Stmt);
1813 end loop;
1815 Loop_Scop := Entity (Identifier (Loop_Stmt));
1817 -- Create the circuitry which verifies individual variants
1819 Variant := First (Pragma_Argument_Associations (N));
1820 while Present (Variant) loop
1821 Process_Variant (Variant, Is_Last => Variant = Last_Var);
1822 Next (Variant);
1823 end loop;
1825 -- Construct the segment which stores the old values of all expressions.
1826 -- Generate:
1827 -- if Flag then
1828 -- <Old_Assign>
1829 -- end if;
1831 Insert_Action (N,
1832 Make_If_Statement (Loc,
1833 Condition => New_Occurrence_Of (Flag_Id, Loc),
1834 Then_Statements => Old_Assign));
1836 -- Update the values of all expressions
1838 Insert_Actions (N, Curr_Assign);
1840 -- Add the assertion circuitry to test all changes in expressions.
1841 -- Generate:
1842 -- if Flag then
1843 -- <If_Stmt>
1844 -- else
1845 -- Flag := True;
1846 -- end if;
1848 Insert_Action (N,
1849 Make_If_Statement (Loc,
1850 Condition => New_Occurrence_Of (Flag_Id, Loc),
1851 Then_Statements => New_List (If_Stmt),
1852 Else_Statements => New_List (
1853 Make_Assignment_Statement (Loc,
1854 Name => New_Occurrence_Of (Flag_Id, Loc),
1855 Expression => New_Occurrence_Of (Standard_True, Loc)))));
1857 -- Note: the pragma has been completely transformed into a sequence of
1858 -- corresponding declarations and statements. We leave it in the tree
1859 -- for documentation purposes. It will be ignored by the backend.
1861 In_Assertion_Expr := In_Assertion_Expr - 1;
1862 end Expand_Pragma_Loop_Variant;
1864 --------------------------------
1865 -- Expand_Pragma_Psect_Object --
1866 --------------------------------
1868 -- Convert to Common_Object, and expand the resulting pragma
1870 procedure Expand_Pragma_Psect_Object (N : Node_Id)
1871 renames Expand_Pragma_Common_Object;
1873 -------------------------------------
1874 -- Expand_Pragma_Relative_Deadline --
1875 -------------------------------------
1877 procedure Expand_Pragma_Relative_Deadline (N : Node_Id) is
1878 P : constant Node_Id := Parent (N);
1879 Loc : constant Source_Ptr := Sloc (N);
1881 begin
1882 -- Expand the pragma only in the case of the main subprogram. For tasks
1883 -- the expansion is done in exp_ch9. Generate a call to Set_Deadline
1884 -- at Clock plus the relative deadline specified in the pragma. Time
1885 -- values are translated into Duration to allow for non-private
1886 -- addition operation.
1888 if Nkind (P) = N_Subprogram_Body then
1889 Rewrite
1891 Make_Procedure_Call_Statement (Loc,
1892 Name => New_Occurrence_Of (RTE (RE_Set_Deadline), Loc),
1893 Parameter_Associations => New_List (
1894 Unchecked_Convert_To (RTE (RO_RT_Time),
1895 Make_Op_Add (Loc,
1896 Left_Opnd =>
1897 Make_Function_Call (Loc,
1898 New_Occurrence_Of (RTE (RO_RT_To_Duration), Loc),
1899 New_List
1900 (Make_Function_Call
1901 (Loc, New_Occurrence_Of (RTE (RE_Clock), Loc)))),
1902 Right_Opnd =>
1903 Unchecked_Convert_To (Standard_Duration, Arg1 (N)))))));
1905 Analyze (N);
1906 end if;
1907 end Expand_Pragma_Relative_Deadline;
1909 -------------------------------------------
1910 -- Expand_Pragma_Suppress_Initialization --
1911 -------------------------------------------
1913 procedure Expand_Pragma_Suppress_Initialization (N : Node_Id) is
1914 Def_Id : constant Entity_Id := Entity (Arg1 (N));
1916 begin
1917 -- Variable case (we have to undo any initialization already done)
1919 if Ekind (Def_Id) = E_Variable then
1920 Undo_Initialization (Def_Id, N);
1921 end if;
1922 end Expand_Pragma_Suppress_Initialization;
1924 -------------------------
1925 -- Undo_Initialization --
1926 -------------------------
1928 procedure Undo_Initialization (Def_Id : Entity_Id; N : Node_Id) is
1929 Init_Call : Node_Id;
1931 begin
1932 -- When applied to a variable, the default initialization must not be
1933 -- done. As it is already done when the pragma is found, we just get rid
1934 -- of the call the initialization procedure which followed the object
1935 -- declaration. The call is inserted after the declaration, but validity
1936 -- checks may also have been inserted and thus the initialization call
1937 -- does not necessarily appear immediately after the object declaration.
1939 -- We can't use the freezing mechanism for this purpose, since we have
1940 -- to elaborate the initialization expression when it is first seen (so
1941 -- this elaboration cannot be deferred to the freeze point).
1943 -- Find and remove generated initialization call for object, if any
1945 Init_Call := Remove_Init_Call (Def_Id, Rep_Clause => N);
1947 -- Any default initialization expression should be removed (e.g.
1948 -- null defaults for access objects, zero initialization of packed
1949 -- bit arrays). Imported objects aren't allowed to have explicit
1950 -- initialization, so the expression must have been generated by
1951 -- the compiler.
1953 if No (Init_Call) and then Present (Expression (Parent (Def_Id))) then
1954 Set_Expression (Parent (Def_Id), Empty);
1955 end if;
1957 -- The object may not have any initialization, but in the presence of
1958 -- Initialize_Scalars code is inserted after then declaration, which
1959 -- must now be removed as well. The code carries the same source
1960 -- location as the declaration itself.
1962 if Initialize_Scalars and then Is_Array_Type (Etype (Def_Id)) then
1963 declare
1964 Init : Node_Id;
1965 Nxt : Node_Id;
1966 begin
1967 Init := Next (Parent (Def_Id));
1968 while not Comes_From_Source (Init)
1969 and then Sloc (Init) = Sloc (Def_Id)
1970 loop
1971 Nxt := Next (Init);
1972 Remove (Init);
1973 Init := Nxt;
1974 end loop;
1975 end;
1976 end if;
1977 end Undo_Initialization;
1979 end Exp_Prag;