2015-09-28 Paul Thomas <pault@gcc.gnu.org>
[official-gcc.git] / gcc / ada / exp_prag.adb
bloba797f230bbfec0fec94ae9b107dbbfc20c12a253
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-2015, 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 Ghost; use Ghost;
36 with Inline; use Inline;
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);
167 begin
168 -- Rewrite pragma ignored by Ignore_Pragma to null statement, so that
169 -- the back end or the expander here does not get overenthusiastic and
170 -- start processing such a pragma!
172 if Get_Name_Table_Boolean3 (Pname) then
173 Rewrite (N, Make_Null_Statement (Sloc (N)));
174 return;
175 end if;
177 -- Note: we may have a pragma whose Pragma_Identifier field is not a
178 -- recognized pragma, and we must ignore it at this stage.
180 if Is_Pragma_Name (Pname) then
181 case Get_Pragma_Id (Pname) 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
220 when others => null;
221 end case;
222 end if;
224 end Expand_N_Pragma;
226 -------------------------------
227 -- Expand_Pragma_Abort_Defer --
228 -------------------------------
230 -- An Abort_Defer pragma appears as the first statement in a handled
231 -- statement sequence (right after the begin). It defers aborts for
232 -- the entire statement sequence, but not for any declarations or
233 -- handlers (if any) associated with this statement sequence.
235 -- The transformation is to transform
237 -- pragma Abort_Defer;
238 -- statements;
240 -- into
242 -- begin
243 -- Abort_Defer.all;
244 -- statements
245 -- exception
246 -- when all others =>
247 -- Abort_Undefer.all;
248 -- raise;
249 -- at end
250 -- Abort_Undefer_Direct;
251 -- end;
253 procedure Expand_Pragma_Abort_Defer (N : Node_Id) is
254 begin
255 -- Abort_Defer has no useful effect if Abort's are not allowed
257 if not Abort_Allowed then
258 return;
259 end if;
261 -- Normal case where abort is possible
263 declare
264 Loc : constant Source_Ptr := Sloc (N);
265 Stm : Node_Id;
266 Stms : List_Id;
267 HSS : Node_Id;
268 Blk : constant Entity_Id :=
269 New_Internal_Entity (E_Block, Current_Scope, Sloc (N), 'B');
270 AUD : constant Entity_Id := RTE (RE_Abort_Undefer_Direct);
272 begin
273 Stms := New_List (Build_Runtime_Call (Loc, RE_Abort_Defer));
274 loop
275 Stm := Remove_Next (N);
276 exit when No (Stm);
277 Append (Stm, Stms);
278 end loop;
280 HSS :=
281 Make_Handled_Sequence_Of_Statements (Loc,
282 Statements => Stms,
283 At_End_Proc => New_Occurrence_Of (AUD, Loc));
285 -- Present the Abort_Undefer_Direct function to the backend so that
286 -- it can inline the call to the function.
288 Add_Inlined_Body (AUD, N);
290 Rewrite (N,
291 Make_Block_Statement (Loc, Handled_Statement_Sequence => HSS));
293 Set_Scope (Blk, Current_Scope);
294 Set_Etype (Blk, Standard_Void_Type);
295 Set_Identifier (N, New_Occurrence_Of (Blk, Sloc (N)));
296 Expand_At_End_Handler (HSS, Blk);
297 Analyze (N);
298 end;
299 end Expand_Pragma_Abort_Defer;
301 --------------------------
302 -- Expand_Pragma_Check --
303 --------------------------
305 procedure Expand_Pragma_Check (N : Node_Id) is
306 GM : constant Ghost_Mode_Type := Ghost_Mode;
307 Cond : constant Node_Id := Arg2 (N);
308 Nam : constant Name_Id := Chars (Arg1 (N));
309 Msg : Node_Id;
311 Loc : constant Source_Ptr := Sloc (First_Node (Cond));
312 -- Source location used in the case of a failed assertion: point to the
313 -- failing condition, not Loc. Note that the source location of the
314 -- expression is not usually the best choice here, because it points to
315 -- the location of the topmost tree node, which may be an operator in
316 -- the middle of the source text of the expression. For example, it gets
317 -- located on the last AND keyword in a chain of boolean expressiond
318 -- AND'ed together. It is best to put the message on the first character
319 -- of the condition, which is the effect of the First_Node call here.
320 -- This source location is used to build the default exception message,
321 -- and also as the sloc of the call to the runtime subprogram raising
322 -- Assert_Failure, so that coverage analysis tools can relate the
323 -- call to the failed check.
325 begin
326 -- Nothing to do if pragma is ignored
328 if Is_Ignored (N) then
329 return;
330 end if;
332 -- Set the Ghost mode in effect from the pragma. In general both the
333 -- assertion policy and the Ghost policy of pragma Check must agree,
334 -- but there are cases where this can be circumvented. For instance,
335 -- a living subtype with an ignored predicate may be declared in one
336 -- packade, an ignored Ghost object in another and the compilation may
337 -- use -gnata to enable assertions.
338 -- ??? Ghost predicates are under redesign
340 Set_Ghost_Mode (N);
342 -- Since this check is active, we rewrite the pragma into a
343 -- corresponding if statement, and then analyze the statement.
345 -- The normal case expansion transforms:
347 -- pragma Check (name, condition [,message]);
349 -- into
351 -- if not condition then
352 -- System.Assertions.Raise_Assert_Failure (Str);
353 -- end if;
355 -- where Str is the message if one is present, or the default of
356 -- name failed at file:line if no message is given (the "name failed
357 -- at" is omitted for name = Assertion, since it is redundant, given
358 -- that the name of the exception is Assert_Failure.)
360 -- Also, instead of "XXX failed at", we generate slightly
361 -- different messages for some of the contract assertions (see
362 -- code below for details).
364 -- An alternative expansion is used when the No_Exception_Propagation
365 -- restriction is active and there is a local Assert_Failure handler.
366 -- This is not a common combination of circumstances, but it occurs in
367 -- the context of Aunit and the zero footprint profile. In this case we
368 -- generate:
370 -- if not condition then
371 -- raise Assert_Failure;
372 -- end if;
374 -- This will then be transformed into a goto, and the local handler will
375 -- be able to handle the assert error (which would not be the case if a
376 -- call is made to the Raise_Assert_Failure procedure).
378 -- We also generate the direct raise if the Suppress_Exception_Locations
379 -- is active, since we don't want to generate messages in this case.
381 -- Note that the reason we do not always generate a direct raise is that
382 -- the form in which the procedure is called allows for more efficient
383 -- breakpointing of assertion errors.
385 -- Generate the appropriate if statement. Note that we consider this to
386 -- be an explicit conditional in the source, not an implicit if, so we
387 -- do not call Make_Implicit_If_Statement.
389 -- Case where we generate a direct raise
391 if ((Debug_Flag_Dot_G
392 or else Restriction_Active (No_Exception_Propagation))
393 and then Present (Find_Local_Handler (RTE (RE_Assert_Failure), N)))
394 or else (Opt.Exception_Locations_Suppressed and then No (Arg3 (N)))
395 then
396 Rewrite (N,
397 Make_If_Statement (Loc,
398 Condition => Make_Op_Not (Loc, Right_Opnd => Cond),
399 Then_Statements => New_List (
400 Make_Raise_Statement (Loc,
401 Name => New_Occurrence_Of (RTE (RE_Assert_Failure), Loc)))));
403 -- Case where we call the procedure
405 else
406 -- If we have a message given, use it
408 if Present (Arg3 (N)) then
409 Msg := Get_Pragma_Arg (Arg3 (N));
411 -- Here we have no string, so prepare one
413 else
414 declare
415 Loc_Str : constant String := Build_Location_String (Loc);
417 begin
418 Name_Len := 0;
420 -- For Assert, we just use the location
422 if Nam = Name_Assert then
423 null;
425 -- For predicate, we generate the string "predicate failed at
426 -- yyy". We prefer all lower case for predicate.
428 elsif Nam = Name_Predicate then
429 Add_Str_To_Name_Buffer ("predicate failed at ");
431 -- For special case of Precondition/Postcondition the string is
432 -- "failed xx from yy" where xx is precondition/postcondition
433 -- in all lower case. The reason for this different wording is
434 -- that the failure is not at the point of occurrence of the
435 -- pragma, unlike the other Check cases.
437 elsif Nam_In (Nam, Name_Precondition, Name_Postcondition) then
438 Get_Name_String (Nam);
439 Insert_Str_In_Name_Buffer ("failed ", 1);
440 Add_Str_To_Name_Buffer (" from ");
442 -- For special case of Invariant, the string is "failed
443 -- invariant from yy", to be consistent with the string that is
444 -- generated for the aspect case (the code later on checks for
445 -- this specific string to modify it in some cases, so this is
446 -- functionally important).
448 elsif Nam = Name_Invariant then
449 Add_Str_To_Name_Buffer ("failed invariant from ");
451 -- For all other checks, the string is "xxx failed at yyy"
452 -- where xxx is the check name with current source file casing.
454 else
455 Get_Name_String (Nam);
456 Set_Casing (Identifier_Casing (Current_Source_File));
457 Add_Str_To_Name_Buffer (" failed at ");
458 end if;
460 -- In all cases, add location string
462 Add_Str_To_Name_Buffer (Loc_Str);
464 -- Build the message
466 Msg := Make_String_Literal (Loc, Name_Buffer (1 .. Name_Len));
467 end;
468 end if;
470 -- Now rewrite as an if statement
472 Rewrite (N,
473 Make_If_Statement (Loc,
474 Condition => Make_Op_Not (Loc, Right_Opnd => Cond),
475 Then_Statements => New_List (
476 Make_Procedure_Call_Statement (Loc,
477 Name =>
478 New_Occurrence_Of (RTE (RE_Raise_Assert_Failure), Loc),
479 Parameter_Associations => New_List (Relocate_Node (Msg))))));
480 end if;
482 Analyze (N);
484 -- If new condition is always false, give a warning
486 if Warn_On_Assertion_Failure
487 and then Nkind (N) = N_Procedure_Call_Statement
488 and then Is_RTE (Entity (Name (N)), RE_Raise_Assert_Failure)
489 then
490 -- If original condition was a Standard.False, we assume that this is
491 -- indeed intended to raise assert error and no warning is required.
493 if Is_Entity_Name (Original_Node (Cond))
494 and then Entity (Original_Node (Cond)) = Standard_False
495 then
496 return;
498 elsif Nam = Name_Assert then
499 Error_Msg_N ("?A?assertion will fail at run time", N);
500 else
502 Error_Msg_N ("?A?check will fail at run time", N);
503 end if;
504 end if;
506 -- Restore the original Ghost mode once analysis and expansion have
507 -- taken place.
509 Ghost_Mode := GM;
510 end Expand_Pragma_Check;
512 ---------------------------------
513 -- Expand_Pragma_Common_Object --
514 ---------------------------------
516 -- Use a machine attribute to replicate semantic effect in DEC Ada
518 -- pragma Machine_Attribute (intern_name, "common_object", extern_name);
520 -- For now we do nothing with the size attribute ???
522 -- Note: Psect_Object shares this processing
524 procedure Expand_Pragma_Common_Object (N : Node_Id) is
525 Loc : constant Source_Ptr := Sloc (N);
527 Internal : constant Node_Id := Arg1 (N);
528 External : constant Node_Id := Arg2 (N);
530 Psect : Node_Id;
531 -- Psect value upper cased as string literal
533 Iloc : constant Source_Ptr := Sloc (Internal);
534 Eloc : constant Source_Ptr := Sloc (External);
535 Ploc : Source_Ptr;
537 begin
538 -- Acquire Psect value and fold to upper case
540 if Present (External) then
541 if Nkind (External) = N_String_Literal then
542 String_To_Name_Buffer (Strval (External));
543 else
544 Get_Name_String (Chars (External));
545 end if;
547 Set_All_Upper_Case;
549 Psect :=
550 Make_String_Literal (Eloc, Strval => String_From_Name_Buffer);
552 else
553 Get_Name_String (Chars (Internal));
554 Set_All_Upper_Case;
555 Psect :=
556 Make_String_Literal (Iloc, Strval => String_From_Name_Buffer);
557 end if;
559 Ploc := Sloc (Psect);
561 -- Insert the pragma
563 Insert_After_And_Analyze (N,
564 Make_Pragma (Loc,
565 Chars => Name_Machine_Attribute,
566 Pragma_Argument_Associations => New_List (
567 Make_Pragma_Argument_Association (Iloc,
568 Expression => New_Copy_Tree (Internal)),
569 Make_Pragma_Argument_Association (Eloc,
570 Expression =>
571 Make_String_Literal (Sloc => Ploc, Strval => "common_object")),
572 Make_Pragma_Argument_Association (Ploc,
573 Expression => New_Copy_Tree (Psect)))));
574 end Expand_Pragma_Common_Object;
576 ----------------------------------
577 -- Expand_Pragma_Contract_Cases --
578 ----------------------------------
580 -- Pragma Contract_Cases is expanded in the following manner:
582 -- subprogram S is
583 -- Count : Natural := 0;
584 -- Flag_1 : Boolean := False;
585 -- . . .
586 -- Flag_N : Boolean := False;
587 -- Flag_N+1 : Boolean := False; -- when "others" present
588 -- Pref_1 : ...;
589 -- . . .
590 -- Pref_M : ...;
592 -- <preconditions (if any)>
594 -- -- Evaluate all case guards
596 -- if Case_Guard_1 then
597 -- Flag_1 := True;
598 -- Count := Count + 1;
599 -- end if;
600 -- . . .
601 -- if Case_Guard_N then
602 -- Flag_N := True;
603 -- Count := Count + 1;
604 -- end if;
606 -- -- Emit errors depending on the number of case guards that
607 -- -- evaluated to True.
609 -- if Count = 0 then
610 -- raise Assertion_Error with "xxx contract cases incomplete";
611 -- <or>
612 -- Flag_N+1 := True; -- when "others" present
614 -- elsif Count > 1 then
615 -- declare
616 -- Str0 : constant String :=
617 -- "contract cases overlap for subprogram ABC";
618 -- Str1 : constant String :=
619 -- (if Flag_1 then
620 -- Str0 & "case guard at xxx evaluates to True"
621 -- else Str0);
622 -- StrN : constant String :=
623 -- (if Flag_N then
624 -- StrN-1 & "case guard at xxx evaluates to True"
625 -- else StrN-1);
626 -- begin
627 -- raise Assertion_Error with StrN;
628 -- end;
629 -- end if;
631 -- -- Evaluate all attribute 'Old prefixes found in the selected
632 -- -- consequence.
634 -- if Flag_1 then
635 -- Pref_1 := <prefix of 'Old found in Consequence_1>
636 -- . . .
637 -- elsif Flag_N then
638 -- Pref_M := <prefix of 'Old found in Consequence_N>
639 -- end if;
641 -- procedure _Postconditions is
642 -- begin
643 -- <postconditions (if any)>
645 -- if Flag_1 and then not Consequence_1 then
646 -- raise Assertion_Error with "failed contract case at xxx";
647 -- end if;
648 -- . . .
649 -- if Flag_N[+1] and then not Consequence_N[+1] then
650 -- raise Assertion_Error with "failed contract case at xxx";
651 -- end if;
652 -- end _Postconditions;
653 -- begin
654 -- . . .
655 -- end S;
657 procedure Expand_Pragma_Contract_Cases
658 (CCs : Node_Id;
659 Subp_Id : Entity_Id;
660 Decls : List_Id;
661 Stmts : in out List_Id)
663 Loc : constant Source_Ptr := Sloc (CCs);
665 procedure Case_Guard_Error
666 (Decls : List_Id;
667 Flag : Entity_Id;
668 Error_Loc : Source_Ptr;
669 Msg : in out Entity_Id);
670 -- Given a declarative list Decls, status flag Flag, the location of the
671 -- error and a string Msg, construct the following check:
672 -- Msg : constant String :=
673 -- (if Flag then
674 -- Msg & "case guard at Error_Loc evaluates to True"
675 -- else Msg);
676 -- The resulting code is added to Decls
678 procedure Consequence_Error
679 (Checks : in out Node_Id;
680 Flag : Entity_Id;
681 Conseq : Node_Id);
682 -- Given an if statement Checks, status flag Flag and a consequence
683 -- Conseq, construct the following check:
684 -- [els]if Flag and then not Conseq then
685 -- raise Assertion_Error
686 -- with "failed contract case at Sloc (Conseq)";
687 -- [end if;]
688 -- The resulting code is added to Checks
690 function Declaration_Of (Id : Entity_Id) return Node_Id;
691 -- Given the entity Id of a boolean flag, generate:
692 -- Id : Boolean := False;
694 procedure Expand_Attributes_In_Consequence
695 (Decls : List_Id;
696 Evals : in out Node_Id;
697 Flag : Entity_Id;
698 Conseq : Node_Id);
699 -- Perform specialized expansion of all attribute 'Old references found
700 -- in consequence Conseq such that at runtime only prefixes coming from
701 -- the selected consequence are evaluated. Similarly expand attribute
702 -- 'Result references by replacing them with identifier _result which
703 -- resolves to the sole formal parameter of procedure _Postconditions.
704 -- Any temporaries generated in the process are added to declarations
705 -- Decls. Evals is a complex if statement tasked with the evaluation of
706 -- all prefixes coming from a single selected consequence. Flag is the
707 -- corresponding case guard flag. Conseq is the consequence expression.
709 function Increment (Id : Entity_Id) return Node_Id;
710 -- Given the entity Id of a numerical variable, generate:
711 -- Id := Id + 1;
713 function Set (Id : Entity_Id) return Node_Id;
714 -- Given the entity Id of a boolean variable, generate:
715 -- Id := True;
717 ----------------------
718 -- Case_Guard_Error --
719 ----------------------
721 procedure Case_Guard_Error
722 (Decls : List_Id;
723 Flag : Entity_Id;
724 Error_Loc : Source_Ptr;
725 Msg : in out Entity_Id)
727 New_Line : constant Character := Character'Val (10);
728 New_Msg : constant Entity_Id := Make_Temporary (Loc, 'S');
730 begin
731 Start_String;
732 Store_String_Char (New_Line);
733 Store_String_Chars (" case guard at ");
734 Store_String_Chars (Build_Location_String (Error_Loc));
735 Store_String_Chars (" evaluates to True");
737 -- Generate:
738 -- New_Msg : constant String :=
739 -- (if Flag then
740 -- Msg & "case guard at Error_Loc evaluates to True"
741 -- else Msg);
743 Append_To (Decls,
744 Make_Object_Declaration (Loc,
745 Defining_Identifier => New_Msg,
746 Constant_Present => True,
747 Object_Definition => New_Occurrence_Of (Standard_String, Loc),
748 Expression =>
749 Make_If_Expression (Loc,
750 Expressions => New_List (
751 New_Occurrence_Of (Flag, Loc),
753 Make_Op_Concat (Loc,
754 Left_Opnd => New_Occurrence_Of (Msg, Loc),
755 Right_Opnd => Make_String_Literal (Loc, End_String)),
757 New_Occurrence_Of (Msg, Loc)))));
759 Msg := New_Msg;
760 end Case_Guard_Error;
762 -----------------------
763 -- Consequence_Error --
764 -----------------------
766 procedure Consequence_Error
767 (Checks : in out Node_Id;
768 Flag : Entity_Id;
769 Conseq : Node_Id)
771 Cond : Node_Id;
772 Error : Node_Id;
774 begin
775 -- Generate:
776 -- Flag and then not Conseq
778 Cond :=
779 Make_And_Then (Loc,
780 Left_Opnd => New_Occurrence_Of (Flag, Loc),
781 Right_Opnd =>
782 Make_Op_Not (Loc,
783 Right_Opnd => Relocate_Node (Conseq)));
785 -- Generate:
786 -- raise Assertion_Error
787 -- with "failed contract case at Sloc (Conseq)";
789 Start_String;
790 Store_String_Chars ("failed contract case at ");
791 Store_String_Chars (Build_Location_String (Sloc (Conseq)));
793 Error :=
794 Make_Procedure_Call_Statement (Loc,
795 Name =>
796 New_Occurrence_Of (RTE (RE_Raise_Assert_Failure), Loc),
797 Parameter_Associations => New_List (
798 Make_String_Literal (Loc, End_String)));
800 if No (Checks) then
801 Checks :=
802 Make_Implicit_If_Statement (CCs,
803 Condition => Cond,
804 Then_Statements => New_List (Error));
806 else
807 if No (Elsif_Parts (Checks)) then
808 Set_Elsif_Parts (Checks, New_List);
809 end if;
811 Append_To (Elsif_Parts (Checks),
812 Make_Elsif_Part (Loc,
813 Condition => Cond,
814 Then_Statements => New_List (Error)));
815 end if;
816 end Consequence_Error;
818 --------------------
819 -- Declaration_Of --
820 --------------------
822 function Declaration_Of (Id : Entity_Id) return Node_Id is
823 begin
824 return
825 Make_Object_Declaration (Loc,
826 Defining_Identifier => Id,
827 Object_Definition => New_Occurrence_Of (Standard_Boolean, Loc),
828 Expression => New_Occurrence_Of (Standard_False, Loc));
829 end Declaration_Of;
831 --------------------------------------
832 -- Expand_Attributes_In_Consequence --
833 --------------------------------------
835 procedure Expand_Attributes_In_Consequence
836 (Decls : List_Id;
837 Evals : in out Node_Id;
838 Flag : Entity_Id;
839 Conseq : Node_Id)
841 Eval_Stmts : List_Id := No_List;
842 -- The evaluation sequence expressed as assignment statements of all
843 -- prefixes of attribute 'Old found in the current consequence.
845 function Expand_Attributes (N : Node_Id) return Traverse_Result;
846 -- Determine whether an arbitrary node denotes attribute 'Old or
847 -- 'Result and if it does, perform all expansion-related actions.
849 -----------------------
850 -- Expand_Attributes --
851 -----------------------
853 function Expand_Attributes (N : Node_Id) return Traverse_Result is
854 Decl : Node_Id;
855 Pref : Node_Id;
856 Temp : Entity_Id;
858 begin
859 -- Attribute 'Old
861 if Nkind (N) = N_Attribute_Reference
862 and then Attribute_Name (N) = Name_Old
863 then
864 Pref := Prefix (N);
865 Temp := Make_Temporary (Loc, 'T', Pref);
866 Set_Etype (Temp, Etype (Pref));
868 -- Generate a temporary to capture the value of the prefix:
869 -- Temp : <Pref type>;
870 -- Place that temporary at the beginning of declarations, to
871 -- prevent anomalies in the GNATprove flow-analysis pass in
872 -- the precondition procedure that follows.
874 Decl :=
875 Make_Object_Declaration (Loc,
876 Defining_Identifier => Temp,
877 Object_Definition =>
878 New_Occurrence_Of (Etype (Pref), Loc));
879 Set_No_Initialization (Decl);
881 Prepend_To (Decls, Decl);
882 Analyze (Decl);
884 -- Evaluate the prefix, generate:
885 -- Temp := <Pref>;
887 if No (Eval_Stmts) then
888 Eval_Stmts := New_List;
889 end if;
891 Append_To (Eval_Stmts,
892 Make_Assignment_Statement (Loc,
893 Name => New_Occurrence_Of (Temp, Loc),
894 Expression => Pref));
896 -- Ensure that the prefix is valid
898 if Validity_Checks_On and then Validity_Check_Operands then
899 Ensure_Valid (Pref);
900 end if;
902 -- Replace the original attribute 'Old by a reference to the
903 -- generated temporary.
905 Rewrite (N, New_Occurrence_Of (Temp, Loc));
907 -- Attribute 'Result
909 elsif Is_Attribute_Result (N) then
910 Rewrite (N, Make_Identifier (Loc, Name_uResult));
911 end if;
913 return OK;
914 end Expand_Attributes;
916 procedure Expand_Attributes_In is
917 new Traverse_Proc (Expand_Attributes);
919 -- Start of processing for Expand_Attributes_In_Consequence
921 begin
922 -- Inspect the consequence and expand any attribute 'Old and 'Result
923 -- references found within.
925 Expand_Attributes_In (Conseq);
927 -- The consequence does not contain any attribute 'Old references
929 if No (Eval_Stmts) then
930 return;
931 end if;
933 -- Augment the machinery to trigger the evaluation of all prefixes
934 -- found in the step above. If Eval is empty, then this is the first
935 -- consequence to yield expansion of 'Old. Generate:
937 -- if Flag then
938 -- <evaluation statements>
939 -- end if;
941 if No (Evals) then
942 Evals :=
943 Make_Implicit_If_Statement (CCs,
944 Condition => New_Occurrence_Of (Flag, Loc),
945 Then_Statements => Eval_Stmts);
947 -- Otherwise generate:
948 -- elsif Flag then
949 -- <evaluation statements>
950 -- end if;
952 else
953 if No (Elsif_Parts (Evals)) then
954 Set_Elsif_Parts (Evals, New_List);
955 end if;
957 Append_To (Elsif_Parts (Evals),
958 Make_Elsif_Part (Loc,
959 Condition => New_Occurrence_Of (Flag, Loc),
960 Then_Statements => Eval_Stmts));
961 end if;
962 end Expand_Attributes_In_Consequence;
964 ---------------
965 -- Increment --
966 ---------------
968 function Increment (Id : Entity_Id) return Node_Id is
969 begin
970 return
971 Make_Assignment_Statement (Loc,
972 Name => New_Occurrence_Of (Id, Loc),
973 Expression =>
974 Make_Op_Add (Loc,
975 Left_Opnd => New_Occurrence_Of (Id, Loc),
976 Right_Opnd => Make_Integer_Literal (Loc, 1)));
977 end Increment;
979 ---------
980 -- Set --
981 ---------
983 function Set (Id : Entity_Id) return Node_Id is
984 begin
985 return
986 Make_Assignment_Statement (Loc,
987 Name => New_Occurrence_Of (Id, Loc),
988 Expression => New_Occurrence_Of (Standard_True, Loc));
989 end Set;
991 -- Local variables
993 Aggr : constant Node_Id :=
994 Expression (First (Pragma_Argument_Associations (CCs)));
995 GM : constant Ghost_Mode_Type := Ghost_Mode;
997 Case_Guard : Node_Id;
998 CG_Checks : Node_Id;
999 CG_Stmts : List_Id;
1000 Conseq : Node_Id;
1001 Conseq_Checks : Node_Id := Empty;
1002 Count : Entity_Id;
1003 Count_Decl : Node_Id;
1004 Error_Decls : List_Id;
1005 Flag : Entity_Id;
1006 Flag_Decl : Node_Id;
1007 If_Stmt : Node_Id;
1008 Msg_Str : Entity_Id;
1009 Multiple_PCs : Boolean;
1010 Old_Evals : Node_Id := Empty;
1011 Others_Decl : Node_Id;
1012 Others_Flag : Entity_Id := Empty;
1013 Post_Case : Node_Id;
1015 -- Start of processing for Expand_Pragma_Contract_Cases
1017 begin
1018 -- Do nothing if pragma is not enabled. If pragma is disabled, it has
1019 -- already been rewritten as a Null statement.
1021 if Is_Ignored (CCs) then
1022 return;
1024 -- Guard against malformed contract cases
1026 elsif Nkind (Aggr) /= N_Aggregate then
1027 return;
1028 end if;
1030 -- The contract cases may be subject to pragma Ghost with policy Ignore.
1031 -- Set the mode now to ensure that any nodes generated during expansion
1032 -- are properly flagged as ignored Ghost.
1034 Set_Ghost_Mode (CCs);
1036 Multiple_PCs := List_Length (Component_Associations (Aggr)) > 1;
1038 -- Create the counter which tracks the number of case guards that
1039 -- evaluate to True.
1041 -- Count : Natural := 0;
1043 Count := Make_Temporary (Loc, 'C');
1044 Count_Decl :=
1045 Make_Object_Declaration (Loc,
1046 Defining_Identifier => Count,
1047 Object_Definition => New_Occurrence_Of (Standard_Natural, Loc),
1048 Expression => Make_Integer_Literal (Loc, 0));
1050 Prepend_To (Decls, Count_Decl);
1051 Analyze (Count_Decl);
1053 -- Create the base error message for multiple overlapping case guards
1055 -- Msg_Str : constant String :=
1056 -- "contract cases overlap for subprogram Subp_Id";
1058 if Multiple_PCs then
1059 Msg_Str := Make_Temporary (Loc, 'S');
1061 Start_String;
1062 Store_String_Chars ("contract cases overlap for subprogram ");
1063 Store_String_Chars (Get_Name_String (Chars (Subp_Id)));
1065 Error_Decls := New_List (
1066 Make_Object_Declaration (Loc,
1067 Defining_Identifier => Msg_Str,
1068 Constant_Present => True,
1069 Object_Definition => New_Occurrence_Of (Standard_String, Loc),
1070 Expression => Make_String_Literal (Loc, End_String)));
1071 end if;
1073 -- Process individual post cases
1075 Post_Case := First (Component_Associations (Aggr));
1076 while Present (Post_Case) loop
1077 Case_Guard := First (Choices (Post_Case));
1078 Conseq := Expression (Post_Case);
1080 -- The "others" choice requires special processing
1082 if Nkind (Case_Guard) = N_Others_Choice then
1083 Others_Flag := Make_Temporary (Loc, 'F');
1084 Others_Decl := Declaration_Of (Others_Flag);
1086 Prepend_To (Decls, Others_Decl);
1087 Analyze (Others_Decl);
1089 -- Check possible overlap between a case guard and "others"
1091 if Multiple_PCs and Exception_Extra_Info then
1092 Case_Guard_Error
1093 (Decls => Error_Decls,
1094 Flag => Others_Flag,
1095 Error_Loc => Sloc (Case_Guard),
1096 Msg => Msg_Str);
1097 end if;
1099 -- Inspect the consequence and perform special expansion of any
1100 -- attribute 'Old and 'Result references found within.
1102 Expand_Attributes_In_Consequence
1103 (Decls => Decls,
1104 Evals => Old_Evals,
1105 Flag => Others_Flag,
1106 Conseq => Conseq);
1108 -- Check the corresponding consequence of "others"
1110 Consequence_Error
1111 (Checks => Conseq_Checks,
1112 Flag => Others_Flag,
1113 Conseq => Conseq);
1115 -- Regular post case
1117 else
1118 -- Create the flag which tracks the state of its associated case
1119 -- guard.
1121 Flag := Make_Temporary (Loc, 'F');
1122 Flag_Decl := Declaration_Of (Flag);
1124 Prepend_To (Decls, Flag_Decl);
1125 Analyze (Flag_Decl);
1127 -- The flag is set when the case guard is evaluated to True
1128 -- if Case_Guard then
1129 -- Flag := True;
1130 -- Count := Count + 1;
1131 -- end if;
1133 If_Stmt :=
1134 Make_Implicit_If_Statement (CCs,
1135 Condition => Relocate_Node (Case_Guard),
1136 Then_Statements => New_List (
1137 Set (Flag),
1138 Increment (Count)));
1140 Append_To (Decls, If_Stmt);
1141 Analyze (If_Stmt);
1143 -- Check whether this case guard overlaps with another one
1145 if Multiple_PCs and Exception_Extra_Info then
1146 Case_Guard_Error
1147 (Decls => Error_Decls,
1148 Flag => Flag,
1149 Error_Loc => Sloc (Case_Guard),
1150 Msg => Msg_Str);
1151 end if;
1153 -- Inspect the consequence and perform special expansion of any
1154 -- attribute 'Old and 'Result references found within.
1156 Expand_Attributes_In_Consequence
1157 (Decls => Decls,
1158 Evals => Old_Evals,
1159 Flag => Flag,
1160 Conseq => Conseq);
1162 -- The corresponding consequence of the case guard which evaluated
1163 -- to True must hold on exit from the subprogram.
1165 Consequence_Error
1166 (Checks => Conseq_Checks,
1167 Flag => Flag,
1168 Conseq => Conseq);
1169 end if;
1171 Next (Post_Case);
1172 end loop;
1174 -- Raise Assertion_Error when none of the case guards evaluate to True.
1175 -- The only exception is when we have "others", in which case there is
1176 -- no error because "others" acts as a default True.
1178 -- Generate:
1179 -- Flag := True;
1181 if Present (Others_Flag) then
1182 CG_Stmts := New_List (Set (Others_Flag));
1184 -- Generate:
1185 -- raise Assertion_Error with "xxx contract cases incomplete";
1187 else
1188 Start_String;
1189 Store_String_Chars (Build_Location_String (Loc));
1190 Store_String_Chars (" contract cases incomplete");
1192 CG_Stmts := New_List (
1193 Make_Procedure_Call_Statement (Loc,
1194 Name =>
1195 New_Occurrence_Of (RTE (RE_Raise_Assert_Failure), Loc),
1196 Parameter_Associations => New_List (
1197 Make_String_Literal (Loc, End_String))));
1198 end if;
1200 CG_Checks :=
1201 Make_Implicit_If_Statement (CCs,
1202 Condition =>
1203 Make_Op_Eq (Loc,
1204 Left_Opnd => New_Occurrence_Of (Count, Loc),
1205 Right_Opnd => Make_Integer_Literal (Loc, 0)),
1206 Then_Statements => CG_Stmts);
1208 -- Detect a possible failure due to several case guards evaluating to
1209 -- True.
1211 -- Generate:
1212 -- elsif Count > 0 then
1213 -- declare
1214 -- <Error_Decls>
1215 -- begin
1216 -- raise Assertion_Error with <Msg_Str>;
1217 -- end if;
1219 if Multiple_PCs then
1220 Set_Elsif_Parts (CG_Checks, New_List (
1221 Make_Elsif_Part (Loc,
1222 Condition =>
1223 Make_Op_Gt (Loc,
1224 Left_Opnd => New_Occurrence_Of (Count, Loc),
1225 Right_Opnd => Make_Integer_Literal (Loc, 1)),
1227 Then_Statements => New_List (
1228 Make_Block_Statement (Loc,
1229 Declarations => Error_Decls,
1230 Handled_Statement_Sequence =>
1231 Make_Handled_Sequence_Of_Statements (Loc,
1232 Statements => New_List (
1233 Make_Procedure_Call_Statement (Loc,
1234 Name =>
1235 New_Occurrence_Of
1236 (RTE (RE_Raise_Assert_Failure), Loc),
1237 Parameter_Associations => New_List (
1238 New_Occurrence_Of (Msg_Str, Loc))))))))));
1239 end if;
1241 Append_To (Decls, CG_Checks);
1242 Analyze (CG_Checks);
1244 -- Once all case guards are evaluated and checked, evaluate any prefixes
1245 -- of attribute 'Old founds in the selected consequence.
1247 if Present (Old_Evals) then
1248 Append_To (Decls, Old_Evals);
1249 Analyze (Old_Evals);
1250 end if;
1252 -- Raise Assertion_Error when the corresponding consequence of a case
1253 -- guard that evaluated to True fails.
1255 if No (Stmts) then
1256 Stmts := New_List;
1257 end if;
1259 Append_To (Stmts, Conseq_Checks);
1261 -- Restore the original Ghost mode once analysis and expansion have
1262 -- taken place.
1264 Ghost_Mode := GM;
1265 end Expand_Pragma_Contract_Cases;
1267 ---------------------------------------
1268 -- Expand_Pragma_Import_Or_Interface --
1269 ---------------------------------------
1271 procedure Expand_Pragma_Import_Or_Interface (N : Node_Id) is
1272 Def_Id : Entity_Id;
1274 begin
1275 -- In Relaxed_RM_Semantics, support old Ada 83 style:
1276 -- pragma Import (Entity, "external name");
1278 if Relaxed_RM_Semantics
1279 and then List_Length (Pragma_Argument_Associations (N)) = 2
1280 and then Chars (Pragma_Identifier (N)) = Name_Import
1281 and then Nkind (Arg2 (N)) = N_String_Literal
1282 then
1283 Def_Id := Entity (Arg1 (N));
1284 else
1285 Def_Id := Entity (Arg2 (N));
1286 end if;
1288 -- Variable case (we have to undo any initialization already done)
1290 if Ekind (Def_Id) = E_Variable then
1291 Undo_Initialization (Def_Id, N);
1293 -- Case of exception with convention C++
1295 elsif Ekind (Def_Id) = E_Exception
1296 and then Convention (Def_Id) = Convention_CPP
1297 then
1298 -- Import a C++ convention
1300 declare
1301 Loc : constant Source_Ptr := Sloc (N);
1302 Rtti_Name : constant Node_Id := Arg3 (N);
1303 Dum : constant Entity_Id := Make_Temporary (Loc, 'D');
1304 Exdata : List_Id;
1305 Lang_Char : Node_Id;
1306 Foreign_Data : Node_Id;
1308 begin
1309 Exdata := Component_Associations (Expression (Parent (Def_Id)));
1311 Lang_Char := Next (First (Exdata));
1313 -- Change the one-character language designator to 'C'
1315 Rewrite (Expression (Lang_Char),
1316 Make_Character_Literal (Loc,
1317 Chars => Name_uC,
1318 Char_Literal_Value => UI_From_Int (Character'Pos ('C'))));
1319 Analyze (Expression (Lang_Char));
1321 -- Change the value of Foreign_Data
1323 Foreign_Data := Next (Next (Next (Next (Lang_Char))));
1325 Insert_Actions (Def_Id, New_List (
1326 Make_Object_Declaration (Loc,
1327 Defining_Identifier => Dum,
1328 Object_Definition =>
1329 New_Occurrence_Of (Standard_Character, Loc)),
1331 Make_Pragma (Loc,
1332 Chars => Name_Import,
1333 Pragma_Argument_Associations => New_List (
1334 Make_Pragma_Argument_Association (Loc,
1335 Expression => Make_Identifier (Loc, Name_Ada)),
1337 Make_Pragma_Argument_Association (Loc,
1338 Expression => Make_Identifier (Loc, Chars (Dum))),
1340 Make_Pragma_Argument_Association (Loc,
1341 Chars => Name_External_Name,
1342 Expression => Relocate_Node (Rtti_Name))))));
1344 Rewrite (Expression (Foreign_Data),
1345 Unchecked_Convert_To (Standard_A_Char,
1346 Make_Attribute_Reference (Loc,
1347 Prefix => Make_Identifier (Loc, Chars (Dum)),
1348 Attribute_Name => Name_Address)));
1349 Analyze (Expression (Foreign_Data));
1350 end;
1352 -- No special expansion required for any other case
1354 else
1355 null;
1356 end if;
1357 end Expand_Pragma_Import_Or_Interface;
1359 -------------------------------------
1360 -- Expand_Pragma_Initial_Condition --
1361 -------------------------------------
1363 procedure Expand_Pragma_Initial_Condition (Spec_Or_Body : Node_Id) is
1364 GM : constant Ghost_Mode_Type := Ghost_Mode;
1366 procedure Restore_Globals;
1367 -- Restore the values of all saved global variables
1369 ---------------------
1370 -- Restore_Globals --
1371 ---------------------
1373 procedure Restore_Globals is
1374 begin
1375 Ghost_Mode := GM;
1376 end Restore_Globals;
1378 -- Local variables
1380 Loc : constant Source_Ptr := Sloc (Spec_Or_Body);
1381 Check : Node_Id;
1382 Expr : Node_Id;
1383 Init_Cond : Node_Id;
1384 List : List_Id;
1385 Pack_Id : Entity_Id;
1387 -- Start of processing for Expand_Pragma_Initial_Condition
1389 begin
1390 if Nkind (Spec_Or_Body) = N_Package_Body then
1391 Pack_Id := Corresponding_Spec (Spec_Or_Body);
1393 if Present (Handled_Statement_Sequence (Spec_Or_Body)) then
1394 List := Statements (Handled_Statement_Sequence (Spec_Or_Body));
1396 -- The package body lacks statements, create an empty list
1398 else
1399 List := New_List;
1401 Set_Handled_Statement_Sequence (Spec_Or_Body,
1402 Make_Handled_Sequence_Of_Statements (Loc, Statements => List));
1403 end if;
1405 elsif Nkind (Spec_Or_Body) = N_Package_Declaration then
1406 Pack_Id := Defining_Entity (Spec_Or_Body);
1408 if Present (Visible_Declarations (Specification (Spec_Or_Body))) then
1409 List := Visible_Declarations (Specification (Spec_Or_Body));
1411 -- The package lacks visible declarations, create an empty list
1413 else
1414 List := New_List;
1416 Set_Visible_Declarations (Specification (Spec_Or_Body), List);
1417 end if;
1419 -- This routine should not be used on anything other than packages
1421 else
1422 raise Program_Error;
1423 end if;
1425 Init_Cond := Get_Pragma (Pack_Id, Pragma_Initial_Condition);
1427 -- The initial condition be subject to pragma Ghost with policy Ignore.
1428 -- Set the mode now to ensure that any nodes generated during expansion
1429 -- are properly flagged as ignored Ghost.
1431 Set_Ghost_Mode (Init_Cond);
1433 -- The caller should check whether the package is subject to pragma
1434 -- Initial_Condition.
1436 pragma Assert (Present (Init_Cond));
1438 Expr :=
1439 Get_Pragma_Arg (First (Pragma_Argument_Associations (Init_Cond)));
1441 -- The assertion expression was found to be illegal, do not generate the
1442 -- runtime check as it will repeat the illegality.
1444 if Error_Posted (Init_Cond) or else Error_Posted (Expr) then
1445 Restore_Globals;
1446 return;
1447 end if;
1449 -- Generate:
1450 -- pragma Check (Initial_Condition, <Expr>);
1452 Check :=
1453 Make_Pragma (Loc,
1454 Chars => Name_Check,
1455 Pragma_Argument_Associations => New_List (
1456 Make_Pragma_Argument_Association (Loc,
1457 Expression => Make_Identifier (Loc, Name_Initial_Condition)),
1458 Make_Pragma_Argument_Association (Loc,
1459 Expression => New_Copy_Tree (Expr))));
1461 Append_To (List, Check);
1462 Analyze (Check);
1464 Restore_Globals;
1465 end Expand_Pragma_Initial_Condition;
1467 ------------------------------------
1468 -- Expand_Pragma_Inspection_Point --
1469 ------------------------------------
1471 -- If no argument is given, then we supply a default argument list that
1472 -- includes all objects declared at the source level in all subprograms
1473 -- that enclose the inspection point pragma.
1475 procedure Expand_Pragma_Inspection_Point (N : Node_Id) is
1476 Loc : constant Source_Ptr := Sloc (N);
1477 A : List_Id;
1478 Assoc : Node_Id;
1479 S : Entity_Id;
1480 E : Entity_Id;
1482 begin
1483 if No (Pragma_Argument_Associations (N)) then
1484 A := New_List;
1485 S := Current_Scope;
1487 while S /= Standard_Standard loop
1488 E := First_Entity (S);
1489 while Present (E) loop
1490 if Comes_From_Source (E)
1491 and then Is_Object (E)
1492 and then not Is_Entry_Formal (E)
1493 and then Ekind (E) /= E_Component
1494 and then Ekind (E) /= E_Discriminant
1495 and then Ekind (E) /= E_Generic_In_Parameter
1496 and then Ekind (E) /= E_Generic_In_Out_Parameter
1497 then
1498 Append_To (A,
1499 Make_Pragma_Argument_Association (Loc,
1500 Expression => New_Occurrence_Of (E, Loc)));
1501 end if;
1503 Next_Entity (E);
1504 end loop;
1506 S := Scope (S);
1507 end loop;
1509 Set_Pragma_Argument_Associations (N, A);
1510 end if;
1512 -- Expand the arguments of the pragma. Expanding an entity reference
1513 -- is a noop, except in a protected operation, where a reference may
1514 -- have to be transformed into a reference to the corresponding prival.
1515 -- Are there other pragmas that may require this ???
1517 Assoc := First (Pragma_Argument_Associations (N));
1518 while Present (Assoc) loop
1519 Expand (Expression (Assoc));
1520 Next (Assoc);
1521 end loop;
1522 end Expand_Pragma_Inspection_Point;
1524 --------------------------------------
1525 -- Expand_Pragma_Interrupt_Priority --
1526 --------------------------------------
1528 -- Supply default argument if none exists (System.Interrupt_Priority'Last)
1530 procedure Expand_Pragma_Interrupt_Priority (N : Node_Id) is
1531 Loc : constant Source_Ptr := Sloc (N);
1532 begin
1533 if No (Pragma_Argument_Associations (N)) then
1534 Set_Pragma_Argument_Associations (N, New_List (
1535 Make_Pragma_Argument_Association (Loc,
1536 Expression =>
1537 Make_Attribute_Reference (Loc,
1538 Prefix =>
1539 New_Occurrence_Of (RTE (RE_Interrupt_Priority), Loc),
1540 Attribute_Name => Name_Last))));
1541 end if;
1542 end Expand_Pragma_Interrupt_Priority;
1544 --------------------------------
1545 -- Expand_Pragma_Loop_Variant --
1546 --------------------------------
1548 -- Pragma Loop_Variant is expanded in the following manner:
1550 -- Original code
1552 -- for | while ... loop
1553 -- <preceding source statements>
1554 -- pragma Loop_Variant
1555 -- (Increases => Incr_Expr,
1556 -- Decreases => Decr_Expr);
1557 -- <succeeding source statements>
1558 -- end loop;
1560 -- Expanded code
1562 -- Curr_1 : <type of Incr_Expr>;
1563 -- Curr_2 : <type of Decr_Expr>;
1564 -- Old_1 : <type of Incr_Expr>;
1565 -- Old_2 : <type of Decr_Expr>;
1566 -- Flag : Boolean := False;
1568 -- for | while ... loop
1569 -- <preceding source statements>
1571 -- if Flag then
1572 -- Old_1 := Curr_1;
1573 -- Old_2 := Curr_2;
1574 -- end if;
1576 -- Curr_1 := <Incr_Expr>;
1577 -- Curr_2 := <Decr_Expr>;
1579 -- if Flag then
1580 -- if Curr_1 /= Old_1 then
1581 -- pragma Check (Loop_Variant, Curr_1 > Old_1);
1582 -- else
1583 -- pragma Check (Loop_Variant, Curr_2 < Old_2);
1584 -- end if;
1585 -- else
1586 -- Flag := True;
1587 -- end if;
1589 -- <succeeding source statements>
1590 -- end loop;
1592 procedure Expand_Pragma_Loop_Variant (N : Node_Id) is
1593 Loc : constant Source_Ptr := Sloc (N);
1594 Last_Var : constant Node_Id :=
1595 Last (Pragma_Argument_Associations (N));
1597 Curr_Assign : List_Id := No_List;
1598 Flag_Id : Entity_Id := Empty;
1599 If_Stmt : Node_Id := Empty;
1600 Old_Assign : List_Id := No_List;
1601 Loop_Scop : Entity_Id;
1602 Loop_Stmt : Node_Id;
1603 Variant : Node_Id;
1605 procedure Process_Variant (Variant : Node_Id; Is_Last : Boolean);
1606 -- Process a single increasing / decreasing termination variant. Flag
1607 -- Is_Last should be set when processing the last variant.
1609 ---------------------
1610 -- Process_Variant --
1611 ---------------------
1613 procedure Process_Variant (Variant : Node_Id; Is_Last : Boolean) is
1614 function Make_Op
1615 (Loc : Source_Ptr;
1616 Curr_Val : Node_Id;
1617 Old_Val : Node_Id) return Node_Id;
1618 -- Generate a comparison between Curr_Val and Old_Val depending on
1619 -- the change mode (Increases / Decreases) of the variant.
1621 -------------
1622 -- Make_Op --
1623 -------------
1625 function Make_Op
1626 (Loc : Source_Ptr;
1627 Curr_Val : Node_Id;
1628 Old_Val : Node_Id) return Node_Id
1630 begin
1631 if Chars (Variant) = Name_Increases then
1632 return Make_Op_Gt (Loc, Curr_Val, Old_Val);
1633 else pragma Assert (Chars (Variant) = Name_Decreases);
1634 return Make_Op_Lt (Loc, Curr_Val, Old_Val);
1635 end if;
1636 end Make_Op;
1638 -- Local variables
1640 Expr : constant Node_Id := Expression (Variant);
1641 Expr_Typ : constant Entity_Id := Etype (Expr);
1642 Loc : constant Source_Ptr := Sloc (Expr);
1643 Loop_Loc : constant Source_Ptr := Sloc (Loop_Stmt);
1644 Curr_Id : Entity_Id;
1645 Old_Id : Entity_Id;
1646 Prag : Node_Id;
1648 -- Start of processing for Process_Variant
1650 begin
1651 -- All temporaries generated in this routine must be inserted before
1652 -- the related loop statement. Ensure that the proper scope is on the
1653 -- stack when analyzing the temporaries. Note that we also use the
1654 -- Sloc of the related loop.
1656 Push_Scope (Scope (Loop_Scop));
1658 -- Step 1: Create the declaration of the flag which controls the
1659 -- behavior of the assertion on the first iteration of the loop.
1661 if No (Flag_Id) then
1663 -- Generate:
1664 -- Flag : Boolean := False;
1666 Flag_Id := Make_Temporary (Loop_Loc, 'F');
1668 Insert_Action (Loop_Stmt,
1669 Make_Object_Declaration (Loop_Loc,
1670 Defining_Identifier => Flag_Id,
1671 Object_Definition =>
1672 New_Occurrence_Of (Standard_Boolean, Loop_Loc),
1673 Expression =>
1674 New_Occurrence_Of (Standard_False, Loop_Loc)));
1676 -- Prevent an unwanted optimization where the Current_Value of
1677 -- the flag eliminates the if statement which stores the variant
1678 -- values coming from the previous iteration.
1680 -- Flag : Boolean := False;
1681 -- loop
1682 -- if Flag then -- condition rewritten to False
1683 -- Old_N := Curr_N; -- and if statement eliminated
1684 -- end if;
1685 -- . . .
1686 -- Flag := True;
1687 -- end loop;
1689 Set_Current_Value (Flag_Id, Empty);
1690 end if;
1692 -- Step 2: Create the temporaries which store the old and current
1693 -- values of the associated expression.
1695 -- Generate:
1696 -- Curr : <type of Expr>;
1698 Curr_Id := Make_Temporary (Loc, 'C');
1700 Insert_Action (Loop_Stmt,
1701 Make_Object_Declaration (Loop_Loc,
1702 Defining_Identifier => Curr_Id,
1703 Object_Definition => New_Occurrence_Of (Expr_Typ, Loop_Loc)));
1705 -- Generate:
1706 -- Old : <type of Expr>;
1708 Old_Id := Make_Temporary (Loc, 'P');
1710 Insert_Action (Loop_Stmt,
1711 Make_Object_Declaration (Loop_Loc,
1712 Defining_Identifier => Old_Id,
1713 Object_Definition => New_Occurrence_Of (Expr_Typ, Loop_Loc)));
1715 -- Restore original scope after all temporaries have been analyzed
1717 Pop_Scope;
1719 -- Step 3: Store value of the expression from the previous iteration
1721 if No (Old_Assign) then
1722 Old_Assign := New_List;
1723 end if;
1725 -- Generate:
1726 -- Old := Curr;
1728 Append_To (Old_Assign,
1729 Make_Assignment_Statement (Loc,
1730 Name => New_Occurrence_Of (Old_Id, Loc),
1731 Expression => New_Occurrence_Of (Curr_Id, Loc)));
1733 -- Step 4: Store the current value of the expression
1735 if No (Curr_Assign) then
1736 Curr_Assign := New_List;
1737 end if;
1739 -- Generate:
1740 -- Curr := <Expr>;
1742 Append_To (Curr_Assign,
1743 Make_Assignment_Statement (Loc,
1744 Name => New_Occurrence_Of (Curr_Id, Loc),
1745 Expression => Relocate_Node (Expr)));
1747 -- Step 5: Create corresponding assertion to verify change of value
1749 -- Generate:
1750 -- pragma Check (Loop_Variant, Curr <|> Old);
1752 Prag :=
1753 Make_Pragma (Loc,
1754 Chars => Name_Check,
1755 Pragma_Argument_Associations => New_List (
1756 Make_Pragma_Argument_Association (Loc,
1757 Expression => Make_Identifier (Loc, Name_Loop_Variant)),
1758 Make_Pragma_Argument_Association (Loc,
1759 Expression =>
1760 Make_Op (Loc,
1761 Curr_Val => New_Occurrence_Of (Curr_Id, Loc),
1762 Old_Val => New_Occurrence_Of (Old_Id, Loc)))));
1764 -- Generate:
1765 -- if Curr /= Old then
1766 -- <Prag>;
1768 if No (If_Stmt) then
1770 -- When there is just one termination variant, do not compare the
1771 -- old and current value for equality, just check the pragma.
1773 if Is_Last then
1774 If_Stmt := Prag;
1775 else
1776 If_Stmt :=
1777 Make_If_Statement (Loc,
1778 Condition =>
1779 Make_Op_Ne (Loc,
1780 Left_Opnd => New_Occurrence_Of (Curr_Id, Loc),
1781 Right_Opnd => New_Occurrence_Of (Old_Id, Loc)),
1782 Then_Statements => New_List (Prag));
1783 end if;
1785 -- Generate:
1786 -- else
1787 -- <Prag>;
1788 -- end if;
1790 elsif Is_Last then
1791 Set_Else_Statements (If_Stmt, New_List (Prag));
1793 -- Generate:
1794 -- elsif Curr /= Old then
1795 -- <Prag>;
1797 else
1798 if Elsif_Parts (If_Stmt) = No_List then
1799 Set_Elsif_Parts (If_Stmt, New_List);
1800 end if;
1802 Append_To (Elsif_Parts (If_Stmt),
1803 Make_Elsif_Part (Loc,
1804 Condition =>
1805 Make_Op_Ne (Loc,
1806 Left_Opnd => New_Occurrence_Of (Curr_Id, Loc),
1807 Right_Opnd => New_Occurrence_Of (Old_Id, Loc)),
1808 Then_Statements => New_List (Prag)));
1809 end if;
1810 end Process_Variant;
1812 -- Local variables
1814 GM : constant Ghost_Mode_Type := Ghost_Mode;
1816 -- Start of processing for Expand_Pragma_Loop_Variant
1818 begin
1819 -- If pragma is not enabled, rewrite as Null statement. If pragma is
1820 -- disabled, it has already been rewritten as a Null statement.
1822 if Is_Ignored (N) then
1823 Rewrite (N, Make_Null_Statement (Loc));
1824 Analyze (N);
1825 return;
1826 end if;
1828 -- The loop variant may be subject to pragma Ghost with policy Ignore.
1829 -- Set the mode now to ensure that any nodes generated during expansion
1830 -- are properly flagged as ignored Ghost.
1832 Set_Ghost_Mode (N);
1834 -- Locate the enclosing loop for which this assertion applies. In the
1835 -- case of Ada 2012 array iteration, we might be dealing with nested
1836 -- loops. Only the outermost loop has an identifier.
1838 Loop_Stmt := N;
1839 while Present (Loop_Stmt) loop
1840 if Nkind (Loop_Stmt) = N_Loop_Statement
1841 and then Present (Identifier (Loop_Stmt))
1842 then
1843 exit;
1844 end if;
1846 Loop_Stmt := Parent (Loop_Stmt);
1847 end loop;
1849 Loop_Scop := Entity (Identifier (Loop_Stmt));
1851 -- Create the circuitry which verifies individual variants
1853 Variant := First (Pragma_Argument_Associations (N));
1854 while Present (Variant) loop
1855 Process_Variant (Variant, Is_Last => Variant = Last_Var);
1856 Next (Variant);
1857 end loop;
1859 -- Construct the segment which stores the old values of all expressions.
1860 -- Generate:
1861 -- if Flag then
1862 -- <Old_Assign>
1863 -- end if;
1865 Insert_Action (N,
1866 Make_If_Statement (Loc,
1867 Condition => New_Occurrence_Of (Flag_Id, Loc),
1868 Then_Statements => Old_Assign));
1870 -- Update the values of all expressions
1872 Insert_Actions (N, Curr_Assign);
1874 -- Add the assertion circuitry to test all changes in expressions.
1875 -- Generate:
1876 -- if Flag then
1877 -- <If_Stmt>
1878 -- else
1879 -- Flag := True;
1880 -- end if;
1882 Insert_Action (N,
1883 Make_If_Statement (Loc,
1884 Condition => New_Occurrence_Of (Flag_Id, Loc),
1885 Then_Statements => New_List (If_Stmt),
1886 Else_Statements => New_List (
1887 Make_Assignment_Statement (Loc,
1888 Name => New_Occurrence_Of (Flag_Id, Loc),
1889 Expression => New_Occurrence_Of (Standard_True, Loc)))));
1891 -- Note: the pragma has been completely transformed into a sequence of
1892 -- corresponding declarations and statements. We leave it in the tree
1893 -- for documentation purposes. It will be ignored by the backend.
1895 -- Restore the original Ghost mode once analysis and expansion have
1896 -- taken place.
1898 Ghost_Mode := GM;
1899 end Expand_Pragma_Loop_Variant;
1901 --------------------------------
1902 -- Expand_Pragma_Psect_Object --
1903 --------------------------------
1905 -- Convert to Common_Object, and expand the resulting pragma
1907 procedure Expand_Pragma_Psect_Object (N : Node_Id)
1908 renames Expand_Pragma_Common_Object;
1910 -------------------------------------
1911 -- Expand_Pragma_Relative_Deadline --
1912 -------------------------------------
1914 procedure Expand_Pragma_Relative_Deadline (N : Node_Id) is
1915 P : constant Node_Id := Parent (N);
1916 Loc : constant Source_Ptr := Sloc (N);
1918 begin
1919 -- Expand the pragma only in the case of the main subprogram. For tasks
1920 -- the expansion is done in exp_ch9. Generate a call to Set_Deadline
1921 -- at Clock plus the relative deadline specified in the pragma. Time
1922 -- values are translated into Duration to allow for non-private
1923 -- addition operation.
1925 if Nkind (P) = N_Subprogram_Body then
1926 Rewrite
1928 Make_Procedure_Call_Statement (Loc,
1929 Name => New_Occurrence_Of (RTE (RE_Set_Deadline), Loc),
1930 Parameter_Associations => New_List (
1931 Unchecked_Convert_To (RTE (RO_RT_Time),
1932 Make_Op_Add (Loc,
1933 Left_Opnd =>
1934 Make_Function_Call (Loc,
1935 New_Occurrence_Of (RTE (RO_RT_To_Duration), Loc),
1936 New_List
1937 (Make_Function_Call
1938 (Loc, New_Occurrence_Of (RTE (RE_Clock), Loc)))),
1939 Right_Opnd =>
1940 Unchecked_Convert_To (Standard_Duration, Arg1 (N)))))));
1942 Analyze (N);
1943 end if;
1944 end Expand_Pragma_Relative_Deadline;
1946 -------------------------------------------
1947 -- Expand_Pragma_Suppress_Initialization --
1948 -------------------------------------------
1950 procedure Expand_Pragma_Suppress_Initialization (N : Node_Id) is
1951 Def_Id : constant Entity_Id := Entity (Arg1 (N));
1953 begin
1954 -- Variable case (we have to undo any initialization already done)
1956 if Ekind (Def_Id) = E_Variable then
1957 Undo_Initialization (Def_Id, N);
1958 end if;
1959 end Expand_Pragma_Suppress_Initialization;
1961 -------------------------
1962 -- Undo_Initialization --
1963 -------------------------
1965 procedure Undo_Initialization (Def_Id : Entity_Id; N : Node_Id) is
1966 Init_Call : Node_Id;
1968 begin
1969 -- When applied to a variable, the default initialization must not be
1970 -- done. As it is already done when the pragma is found, we just get rid
1971 -- of the call the initialization procedure which followed the object
1972 -- declaration. The call is inserted after the declaration, but validity
1973 -- checks may also have been inserted and thus the initialization call
1974 -- does not necessarily appear immediately after the object declaration.
1976 -- We can't use the freezing mechanism for this purpose, since we have
1977 -- to elaborate the initialization expression when it is first seen (so
1978 -- this elaboration cannot be deferred to the freeze point).
1980 -- Find and remove generated initialization call for object, if any
1982 Init_Call := Remove_Init_Call (Def_Id, Rep_Clause => N);
1984 -- Any default initialization expression should be removed (e.g.
1985 -- null defaults for access objects, zero initialization of packed
1986 -- bit arrays). Imported objects aren't allowed to have explicit
1987 -- initialization, so the expression must have been generated by
1988 -- the compiler.
1990 if No (Init_Call) and then Present (Expression (Parent (Def_Id))) then
1991 Set_Expression (Parent (Def_Id), Empty);
1992 end if;
1994 -- The object may not have any initialization, but in the presence of
1995 -- Initialize_Scalars code is inserted after then declaration, which
1996 -- must now be removed as well. The code carries the same source
1997 -- location as the declaration itself.
1999 if Initialize_Scalars and then Is_Array_Type (Etype (Def_Id)) then
2000 declare
2001 Init : Node_Id;
2002 Nxt : Node_Id;
2003 begin
2004 Init := Next (Parent (Def_Id));
2005 while not Comes_From_Source (Init)
2006 and then Sloc (Init) = Sloc (Def_Id)
2007 loop
2008 Nxt := Next (Init);
2009 Remove (Init);
2010 Init := Nxt;
2011 end loop;
2012 end;
2013 end if;
2014 end Undo_Initialization;
2016 end Exp_Prag;