PR c++/79377
[official-gcc.git] / gcc / ada / exp_prag.adb
blobe2a6753003e357d52ae944755bdf0a1e26c41486
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-2016, 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 Namet; use Namet;
37 with Nlists; use Nlists;
38 with Nmake; use Nmake;
39 with Opt; use Opt;
40 with Restrict; use Restrict;
41 with Rident; use Rident;
42 with Rtsfind; use Rtsfind;
43 with Sem; use Sem;
44 with Sem_Ch8; use Sem_Ch8;
45 with Sem_Util; use Sem_Util;
46 with Sinfo; use Sinfo;
47 with Sinput; use Sinput;
48 with Snames; use Snames;
49 with Stringt; use Stringt;
50 with Stand; use Stand;
51 with Tbuild; use Tbuild;
52 with Uintp; use Uintp;
53 with Validsw; use Validsw;
55 package body Exp_Prag is
57 -----------------------
58 -- Local Subprograms --
59 -----------------------
61 function Arg1 (N : Node_Id) return Node_Id;
62 function Arg2 (N : Node_Id) return Node_Id;
63 function Arg3 (N : Node_Id) return Node_Id;
64 -- Obtain specified pragma argument expression
66 procedure Expand_Pragma_Abort_Defer (N : Node_Id);
67 procedure Expand_Pragma_Check (N : Node_Id);
68 procedure Expand_Pragma_Common_Object (N : Node_Id);
69 procedure Expand_Pragma_Import_Or_Interface (N : Node_Id);
70 procedure Expand_Pragma_Inspection_Point (N : Node_Id);
71 procedure Expand_Pragma_Interrupt_Priority (N : Node_Id);
72 procedure Expand_Pragma_Loop_Variant (N : Node_Id);
73 procedure Expand_Pragma_Psect_Object (N : Node_Id);
74 procedure Expand_Pragma_Relative_Deadline (N : Node_Id);
75 procedure Expand_Pragma_Suppress_Initialization (N : Node_Id);
77 procedure Undo_Initialization (Def_Id : Entity_Id; N : Node_Id);
78 -- This procedure is used to undo initialization already done for Def_Id,
79 -- which is always an E_Variable, in response to the occurrence of the
80 -- pragma N, a pragma Interface, Import, or Suppress_Initialization. In all
81 -- these cases we want no initialization to occur, but we have already done
82 -- the initialization by the time we see the pragma, so we have to undo it.
84 ----------
85 -- Arg1 --
86 ----------
88 function Arg1 (N : Node_Id) return Node_Id is
89 Arg : constant Node_Id := First (Pragma_Argument_Associations (N));
90 begin
91 if Present (Arg)
92 and then Nkind (Arg) = N_Pragma_Argument_Association
93 then
94 return Expression (Arg);
95 else
96 return Arg;
97 end if;
98 end Arg1;
100 ----------
101 -- Arg2 --
102 ----------
104 function Arg2 (N : Node_Id) return Node_Id is
105 Arg1 : constant Node_Id := First (Pragma_Argument_Associations (N));
107 begin
108 if No (Arg1) then
109 return Empty;
111 else
112 declare
113 Arg : constant Node_Id := Next (Arg1);
114 begin
115 if Present (Arg)
116 and then Nkind (Arg) = N_Pragma_Argument_Association
117 then
118 return Expression (Arg);
119 else
120 return Arg;
121 end if;
122 end;
123 end if;
124 end Arg2;
126 ----------
127 -- Arg3 --
128 ----------
130 function Arg3 (N : Node_Id) return Node_Id is
131 Arg1 : constant Node_Id := First (Pragma_Argument_Associations (N));
133 begin
134 if No (Arg1) then
135 return Empty;
137 else
138 declare
139 Arg : Node_Id := Next (Arg1);
140 begin
141 if No (Arg) then
142 return Empty;
144 else
145 Next (Arg);
147 if Present (Arg)
148 and then Nkind (Arg) = N_Pragma_Argument_Association
149 then
150 return Expression (Arg);
151 else
152 return Arg;
153 end if;
154 end if;
155 end;
156 end if;
157 end Arg3;
159 ---------------------
160 -- Expand_N_Pragma --
161 ---------------------
163 procedure Expand_N_Pragma (N : Node_Id) is
164 Pname : constant Name_Id := Pragma_Name (N);
166 begin
167 -- Rewrite pragma ignored by Ignore_Pragma to null statement, so that
168 -- the back end or the expander here does not get overenthusiastic and
169 -- start processing such a pragma!
171 if Get_Name_Table_Boolean3 (Pname) then
172 Rewrite (N, Make_Null_Statement (Sloc (N)));
173 return;
174 end if;
176 case Get_Pragma_Id (Pname) is
178 -- Pragmas requiring special expander action
180 when Pragma_Abort_Defer =>
181 Expand_Pragma_Abort_Defer (N);
183 when Pragma_Check =>
184 Expand_Pragma_Check (N);
186 when Pragma_Common_Object =>
187 Expand_Pragma_Common_Object (N);
189 when Pragma_Import =>
190 Expand_Pragma_Import_Or_Interface (N);
192 when Pragma_Inspection_Point =>
193 Expand_Pragma_Inspection_Point (N);
195 when Pragma_Interface =>
196 Expand_Pragma_Import_Or_Interface (N);
198 when Pragma_Interrupt_Priority =>
199 Expand_Pragma_Interrupt_Priority (N);
201 when Pragma_Loop_Variant =>
202 Expand_Pragma_Loop_Variant (N);
204 when Pragma_Psect_Object =>
205 Expand_Pragma_Psect_Object (N);
207 when Pragma_Relative_Deadline =>
208 Expand_Pragma_Relative_Deadline (N);
210 when Pragma_Suppress_Initialization =>
211 Expand_Pragma_Suppress_Initialization (N);
213 -- All other pragmas need no expander action (includes
214 -- Unknown_Pragma).
216 when others => null;
217 end case;
218 end Expand_N_Pragma;
220 -------------------------------
221 -- Expand_Pragma_Abort_Defer --
222 -------------------------------
224 -- An Abort_Defer pragma appears as the first statement in a handled
225 -- statement sequence (right after the begin). It defers aborts for
226 -- the entire statement sequence, but not for any declarations or
227 -- handlers (if any) associated with this statement sequence.
229 -- The transformation is to transform
231 -- pragma Abort_Defer;
232 -- statements;
234 -- into
236 -- begin
237 -- Abort_Defer.all;
238 -- statements
239 -- exception
240 -- when all others =>
241 -- Abort_Undefer.all;
242 -- raise;
243 -- at end
244 -- Abort_Undefer_Direct;
245 -- end;
247 procedure Expand_Pragma_Abort_Defer (N : Node_Id) is
248 begin
249 -- Abort_Defer has no useful effect if Abort's are not allowed
251 if not Abort_Allowed then
252 return;
253 end if;
255 -- Normal case where abort is possible
257 declare
258 Loc : constant Source_Ptr := Sloc (N);
259 Stm : Node_Id;
260 Stms : List_Id;
261 HSS : Node_Id;
262 Blk : constant Entity_Id :=
263 New_Internal_Entity (E_Block, Current_Scope, Sloc (N), 'B');
264 AUD : constant Entity_Id := RTE (RE_Abort_Undefer_Direct);
266 begin
267 Stms := New_List (Build_Runtime_Call (Loc, RE_Abort_Defer));
268 loop
269 Stm := Remove_Next (N);
270 exit when No (Stm);
271 Append (Stm, Stms);
272 end loop;
274 HSS :=
275 Make_Handled_Sequence_Of_Statements (Loc,
276 Statements => Stms,
277 At_End_Proc => New_Occurrence_Of (AUD, Loc));
279 -- Present the Abort_Undefer_Direct function to the backend so that
280 -- it can inline the call to the function.
282 Add_Inlined_Body (AUD, N);
284 Rewrite (N,
285 Make_Block_Statement (Loc, Handled_Statement_Sequence => HSS));
287 Set_Scope (Blk, Current_Scope);
288 Set_Etype (Blk, Standard_Void_Type);
289 Set_Identifier (N, New_Occurrence_Of (Blk, Sloc (N)));
290 Expand_At_End_Handler (HSS, Blk);
291 Analyze (N);
292 end;
293 end Expand_Pragma_Abort_Defer;
295 --------------------------
296 -- Expand_Pragma_Check --
297 --------------------------
299 procedure Expand_Pragma_Check (N : Node_Id) is
300 Cond : constant Node_Id := Arg2 (N);
301 Nam : constant Name_Id := Chars (Arg1 (N));
302 Msg : Node_Id;
304 Loc : constant Source_Ptr := Sloc (First_Node (Cond));
305 -- Source location used in the case of a failed assertion: point to the
306 -- failing condition, not Loc. Note that the source location of the
307 -- expression is not usually the best choice here, because it points to
308 -- the location of the topmost tree node, which may be an operator in
309 -- the middle of the source text of the expression. For example, it gets
310 -- located on the last AND keyword in a chain of boolean expressiond
311 -- AND'ed together. It is best to put the message on the first character
312 -- of the condition, which is the effect of the First_Node call here.
313 -- This source location is used to build the default exception message,
314 -- and also as the sloc of the call to the runtime subprogram raising
315 -- Assert_Failure, so that coverage analysis tools can relate the
316 -- call to the failed check.
318 begin
319 -- Nothing to do if pragma is ignored
321 if Is_Ignored (N) then
322 return;
323 end if;
325 -- Since this check is active, rewrite the pragma into a corresponding
326 -- if statement, and then analyze the statement.
328 -- The normal case expansion transforms:
330 -- pragma Check (name, condition [,message]);
332 -- into
334 -- if not condition then
335 -- System.Assertions.Raise_Assert_Failure (Str);
336 -- end if;
338 -- where Str is the message if one is present, or the default of
339 -- name failed at file:line if no message is given (the "name failed
340 -- at" is omitted for name = Assertion, since it is redundant, given
341 -- that the name of the exception is Assert_Failure.)
343 -- Also, instead of "XXX failed at", we generate slightly
344 -- different messages for some of the contract assertions (see
345 -- code below for details).
347 -- An alternative expansion is used when the No_Exception_Propagation
348 -- restriction is active and there is a local Assert_Failure handler.
349 -- This is not a common combination of circumstances, but it occurs in
350 -- the context of Aunit and the zero footprint profile. In this case we
351 -- generate:
353 -- if not condition then
354 -- raise Assert_Failure;
355 -- end if;
357 -- This will then be transformed into a goto, and the local handler will
358 -- be able to handle the assert error (which would not be the case if a
359 -- call is made to the Raise_Assert_Failure procedure).
361 -- We also generate the direct raise if the Suppress_Exception_Locations
362 -- is active, since we don't want to generate messages in this case.
364 -- Note that the reason we do not always generate a direct raise is that
365 -- the form in which the procedure is called allows for more efficient
366 -- breakpointing of assertion errors.
368 -- Generate the appropriate if statement. Note that we consider this to
369 -- be an explicit conditional in the source, not an implicit if, so we
370 -- do not call Make_Implicit_If_Statement.
372 -- Case where we generate a direct raise
374 if ((Debug_Flag_Dot_G
375 or else Restriction_Active (No_Exception_Propagation))
376 and then Present (Find_Local_Handler (RTE (RE_Assert_Failure), N)))
377 or else (Opt.Exception_Locations_Suppressed and then No (Arg3 (N)))
378 then
379 Rewrite (N,
380 Make_If_Statement (Loc,
381 Condition => Make_Op_Not (Loc, Right_Opnd => Cond),
382 Then_Statements => New_List (
383 Make_Raise_Statement (Loc,
384 Name => New_Occurrence_Of (RTE (RE_Assert_Failure), Loc)))));
386 -- Case where we call the procedure
388 else
389 -- If we have a message given, use it
391 if Present (Arg3 (N)) then
392 Msg := Get_Pragma_Arg (Arg3 (N));
394 -- Here we have no string, so prepare one
396 else
397 declare
398 Loc_Str : constant String := Build_Location_String (Loc);
400 begin
401 Name_Len := 0;
403 -- For Assert, we just use the location
405 if Nam = Name_Assert then
406 null;
408 -- For predicate, we generate the string "predicate failed at
409 -- yyy". We prefer all lower case for predicate.
411 elsif Nam = Name_Predicate then
412 Add_Str_To_Name_Buffer ("predicate failed at ");
414 -- For special case of Precondition/Postcondition the string is
415 -- "failed xx from yy" where xx is precondition/postcondition
416 -- in all lower case. The reason for this different wording is
417 -- that the failure is not at the point of occurrence of the
418 -- pragma, unlike the other Check cases.
420 elsif Nam_In (Nam, Name_Precondition, Name_Postcondition) then
421 Get_Name_String (Nam);
422 Insert_Str_In_Name_Buffer ("failed ", 1);
423 Add_Str_To_Name_Buffer (" from ");
425 -- For special case of Invariant, the string is "failed
426 -- invariant from yy", to be consistent with the string that is
427 -- generated for the aspect case (the code later on checks for
428 -- this specific string to modify it in some cases, so this is
429 -- functionally important).
431 elsif Nam = Name_Invariant then
432 Add_Str_To_Name_Buffer ("failed invariant from ");
434 -- For all other checks, the string is "xxx failed at yyy"
435 -- where xxx is the check name with current source file casing.
437 else
438 Get_Name_String (Nam);
439 Set_Casing (Identifier_Casing (Current_Source_File));
440 Add_Str_To_Name_Buffer (" failed at ");
441 end if;
443 -- In all cases, add location string
445 Add_Str_To_Name_Buffer (Loc_Str);
447 -- Build the message
449 Msg := Make_String_Literal (Loc, Name_Buffer (1 .. Name_Len));
450 end;
451 end if;
453 -- Now rewrite as an if statement
455 Rewrite (N,
456 Make_If_Statement (Loc,
457 Condition => Make_Op_Not (Loc, Right_Opnd => Cond),
458 Then_Statements => New_List (
459 Make_Procedure_Call_Statement (Loc,
460 Name =>
461 New_Occurrence_Of (RTE (RE_Raise_Assert_Failure), Loc),
462 Parameter_Associations => New_List (Relocate_Node (Msg))))));
463 end if;
465 Analyze (N);
467 -- If new condition is always false, give a warning
469 if Warn_On_Assertion_Failure
470 and then Nkind (N) = N_Procedure_Call_Statement
471 and then Is_RTE (Entity (Name (N)), RE_Raise_Assert_Failure)
472 then
473 -- If original condition was a Standard.False, we assume that this is
474 -- indeed intended to raise assert error and no warning is required.
476 if Is_Entity_Name (Original_Node (Cond))
477 and then Entity (Original_Node (Cond)) = Standard_False
478 then
479 null;
481 elsif Nam = Name_Assert then
482 Error_Msg_N ("?A?assertion will fail at run time", N);
483 else
484 Error_Msg_N ("?A?check will fail at run time", N);
485 end if;
486 end if;
487 end Expand_Pragma_Check;
489 ---------------------------------
490 -- Expand_Pragma_Common_Object --
491 ---------------------------------
493 -- Use a machine attribute to replicate semantic effect in DEC Ada
495 -- pragma Machine_Attribute (intern_name, "common_object", extern_name);
497 -- For now we do nothing with the size attribute ???
499 -- Note: Psect_Object shares this processing
501 procedure Expand_Pragma_Common_Object (N : Node_Id) is
502 Loc : constant Source_Ptr := Sloc (N);
504 Internal : constant Node_Id := Arg1 (N);
505 External : constant Node_Id := Arg2 (N);
507 Psect : Node_Id;
508 -- Psect value upper cased as string literal
510 Iloc : constant Source_Ptr := Sloc (Internal);
511 Eloc : constant Source_Ptr := Sloc (External);
512 Ploc : Source_Ptr;
514 begin
515 -- Acquire Psect value and fold to upper case
517 if Present (External) then
518 if Nkind (External) = N_String_Literal then
519 String_To_Name_Buffer (Strval (External));
520 else
521 Get_Name_String (Chars (External));
522 end if;
524 Set_All_Upper_Case;
526 Psect :=
527 Make_String_Literal (Eloc, Strval => String_From_Name_Buffer);
529 else
530 Get_Name_String (Chars (Internal));
531 Set_All_Upper_Case;
532 Psect :=
533 Make_String_Literal (Iloc, Strval => String_From_Name_Buffer);
534 end if;
536 Ploc := Sloc (Psect);
538 -- Insert the pragma
540 Insert_After_And_Analyze (N,
541 Make_Pragma (Loc,
542 Chars => Name_Machine_Attribute,
543 Pragma_Argument_Associations => New_List (
544 Make_Pragma_Argument_Association (Iloc,
545 Expression => New_Copy_Tree (Internal)),
546 Make_Pragma_Argument_Association (Eloc,
547 Expression =>
548 Make_String_Literal (Sloc => Ploc, Strval => "common_object")),
549 Make_Pragma_Argument_Association (Ploc,
550 Expression => New_Copy_Tree (Psect)))));
551 end Expand_Pragma_Common_Object;
553 ----------------------------------
554 -- Expand_Pragma_Contract_Cases --
555 ----------------------------------
557 -- Pragma Contract_Cases is expanded in the following manner:
559 -- subprogram S is
560 -- Count : Natural := 0;
561 -- Flag_1 : Boolean := False;
562 -- . . .
563 -- Flag_N : Boolean := False;
564 -- Flag_N+1 : Boolean := False; -- when "others" present
565 -- Pref_1 : ...;
566 -- . . .
567 -- Pref_M : ...;
569 -- <preconditions (if any)>
571 -- -- Evaluate all case guards
573 -- if Case_Guard_1 then
574 -- Flag_1 := True;
575 -- Count := Count + 1;
576 -- end if;
577 -- . . .
578 -- if Case_Guard_N then
579 -- Flag_N := True;
580 -- Count := Count + 1;
581 -- end if;
583 -- -- Emit errors depending on the number of case guards that
584 -- -- evaluated to True.
586 -- if Count = 0 then
587 -- raise Assertion_Error with "xxx contract cases incomplete";
588 -- <or>
589 -- Flag_N+1 := True; -- when "others" present
591 -- elsif Count > 1 then
592 -- declare
593 -- Str0 : constant String :=
594 -- "contract cases overlap for subprogram ABC";
595 -- Str1 : constant String :=
596 -- (if Flag_1 then
597 -- Str0 & "case guard at xxx evaluates to True"
598 -- else Str0);
599 -- StrN : constant String :=
600 -- (if Flag_N then
601 -- StrN-1 & "case guard at xxx evaluates to True"
602 -- else StrN-1);
603 -- begin
604 -- raise Assertion_Error with StrN;
605 -- end;
606 -- end if;
608 -- -- Evaluate all attribute 'Old prefixes found in the selected
609 -- -- consequence.
611 -- if Flag_1 then
612 -- Pref_1 := <prefix of 'Old found in Consequence_1>
613 -- . . .
614 -- elsif Flag_N then
615 -- Pref_M := <prefix of 'Old found in Consequence_N>
616 -- end if;
618 -- procedure _Postconditions is
619 -- begin
620 -- <postconditions (if any)>
622 -- if Flag_1 and then not Consequence_1 then
623 -- raise Assertion_Error with "failed contract case at xxx";
624 -- end if;
625 -- . . .
626 -- if Flag_N[+1] and then not Consequence_N[+1] then
627 -- raise Assertion_Error with "failed contract case at xxx";
628 -- end if;
629 -- end _Postconditions;
630 -- begin
631 -- . . .
632 -- end S;
634 procedure Expand_Pragma_Contract_Cases
635 (CCs : Node_Id;
636 Subp_Id : Entity_Id;
637 Decls : List_Id;
638 Stmts : in out List_Id)
640 Loc : constant Source_Ptr := Sloc (CCs);
642 procedure Case_Guard_Error
643 (Decls : List_Id;
644 Flag : Entity_Id;
645 Error_Loc : Source_Ptr;
646 Msg : in out Entity_Id);
647 -- Given a declarative list Decls, status flag Flag, the location of the
648 -- error and a string Msg, construct the following check:
649 -- Msg : constant String :=
650 -- (if Flag then
651 -- Msg & "case guard at Error_Loc evaluates to True"
652 -- else Msg);
653 -- The resulting code is added to Decls
655 procedure Consequence_Error
656 (Checks : in out Node_Id;
657 Flag : Entity_Id;
658 Conseq : Node_Id);
659 -- Given an if statement Checks, status flag Flag and a consequence
660 -- Conseq, construct the following check:
661 -- [els]if Flag and then not Conseq then
662 -- raise Assertion_Error
663 -- with "failed contract case at Sloc (Conseq)";
664 -- [end if;]
665 -- The resulting code is added to Checks
667 function Declaration_Of (Id : Entity_Id) return Node_Id;
668 -- Given the entity Id of a boolean flag, generate:
669 -- Id : Boolean := False;
671 procedure Expand_Attributes_In_Consequence
672 (Decls : List_Id;
673 Evals : in out Node_Id;
674 Flag : Entity_Id;
675 Conseq : Node_Id);
676 -- Perform specialized expansion of all attribute 'Old references found
677 -- in consequence Conseq such that at runtime only prefixes coming from
678 -- the selected consequence are evaluated. Similarly expand attribute
679 -- 'Result references by replacing them with identifier _result which
680 -- resolves to the sole formal parameter of procedure _Postconditions.
681 -- Any temporaries generated in the process are added to declarations
682 -- Decls. Evals is a complex if statement tasked with the evaluation of
683 -- all prefixes coming from a single selected consequence. Flag is the
684 -- corresponding case guard flag. Conseq is the consequence expression.
686 function Increment (Id : Entity_Id) return Node_Id;
687 -- Given the entity Id of a numerical variable, generate:
688 -- Id := Id + 1;
690 function Set (Id : Entity_Id) return Node_Id;
691 -- Given the entity Id of a boolean variable, generate:
692 -- Id := True;
694 ----------------------
695 -- Case_Guard_Error --
696 ----------------------
698 procedure Case_Guard_Error
699 (Decls : List_Id;
700 Flag : Entity_Id;
701 Error_Loc : Source_Ptr;
702 Msg : in out Entity_Id)
704 New_Line : constant Character := Character'Val (10);
705 New_Msg : constant Entity_Id := Make_Temporary (Loc, 'S');
707 begin
708 Start_String;
709 Store_String_Char (New_Line);
710 Store_String_Chars (" case guard at ");
711 Store_String_Chars (Build_Location_String (Error_Loc));
712 Store_String_Chars (" evaluates to True");
714 -- Generate:
715 -- New_Msg : constant String :=
716 -- (if Flag then
717 -- Msg & "case guard at Error_Loc evaluates to True"
718 -- else Msg);
720 Append_To (Decls,
721 Make_Object_Declaration (Loc,
722 Defining_Identifier => New_Msg,
723 Constant_Present => True,
724 Object_Definition => New_Occurrence_Of (Standard_String, Loc),
725 Expression =>
726 Make_If_Expression (Loc,
727 Expressions => New_List (
728 New_Occurrence_Of (Flag, Loc),
730 Make_Op_Concat (Loc,
731 Left_Opnd => New_Occurrence_Of (Msg, Loc),
732 Right_Opnd => Make_String_Literal (Loc, End_String)),
734 New_Occurrence_Of (Msg, Loc)))));
736 Msg := New_Msg;
737 end Case_Guard_Error;
739 -----------------------
740 -- Consequence_Error --
741 -----------------------
743 procedure Consequence_Error
744 (Checks : in out Node_Id;
745 Flag : Entity_Id;
746 Conseq : Node_Id)
748 Cond : Node_Id;
749 Error : Node_Id;
751 begin
752 -- Generate:
753 -- Flag and then not Conseq
755 Cond :=
756 Make_And_Then (Loc,
757 Left_Opnd => New_Occurrence_Of (Flag, Loc),
758 Right_Opnd =>
759 Make_Op_Not (Loc,
760 Right_Opnd => Relocate_Node (Conseq)));
762 -- Generate:
763 -- raise Assertion_Error
764 -- with "failed contract case at Sloc (Conseq)";
766 Start_String;
767 Store_String_Chars ("failed contract case at ");
768 Store_String_Chars (Build_Location_String (Sloc (Conseq)));
770 Error :=
771 Make_Procedure_Call_Statement (Loc,
772 Name =>
773 New_Occurrence_Of (RTE (RE_Raise_Assert_Failure), Loc),
774 Parameter_Associations => New_List (
775 Make_String_Literal (Loc, End_String)));
777 if No (Checks) then
778 Checks :=
779 Make_Implicit_If_Statement (CCs,
780 Condition => Cond,
781 Then_Statements => New_List (Error));
783 else
784 if No (Elsif_Parts (Checks)) then
785 Set_Elsif_Parts (Checks, New_List);
786 end if;
788 Append_To (Elsif_Parts (Checks),
789 Make_Elsif_Part (Loc,
790 Condition => Cond,
791 Then_Statements => New_List (Error)));
792 end if;
793 end Consequence_Error;
795 --------------------
796 -- Declaration_Of --
797 --------------------
799 function Declaration_Of (Id : Entity_Id) return Node_Id is
800 begin
801 return
802 Make_Object_Declaration (Loc,
803 Defining_Identifier => Id,
804 Object_Definition => New_Occurrence_Of (Standard_Boolean, Loc),
805 Expression => New_Occurrence_Of (Standard_False, Loc));
806 end Declaration_Of;
808 --------------------------------------
809 -- Expand_Attributes_In_Consequence --
810 --------------------------------------
812 procedure Expand_Attributes_In_Consequence
813 (Decls : List_Id;
814 Evals : in out Node_Id;
815 Flag : Entity_Id;
816 Conseq : Node_Id)
818 Eval_Stmts : List_Id := No_List;
819 -- The evaluation sequence expressed as assignment statements of all
820 -- prefixes of attribute 'Old found in the current consequence.
822 function Expand_Attributes (N : Node_Id) return Traverse_Result;
823 -- Determine whether an arbitrary node denotes attribute 'Old or
824 -- 'Result and if it does, perform all expansion-related actions.
826 -----------------------
827 -- Expand_Attributes --
828 -----------------------
830 function Expand_Attributes (N : Node_Id) return Traverse_Result is
831 Decl : Node_Id;
832 Pref : Node_Id;
833 Temp : Entity_Id;
835 begin
836 -- Attribute 'Old
838 if Nkind (N) = N_Attribute_Reference
839 and then Attribute_Name (N) = Name_Old
840 then
841 Pref := Prefix (N);
842 Temp := Make_Temporary (Loc, 'T', Pref);
843 Set_Etype (Temp, Etype (Pref));
845 -- Generate a temporary to capture the value of the prefix:
846 -- Temp : <Pref type>;
848 Decl :=
849 Make_Object_Declaration (Loc,
850 Defining_Identifier => Temp,
851 Object_Definition =>
852 New_Occurrence_Of (Etype (Pref), Loc));
854 -- Place that temporary at the beginning of declarations, to
855 -- prevent anomalies in the GNATprove flow-analysis pass in
856 -- the precondition procedure that follows.
858 Prepend_To (Decls, Decl);
860 -- If the type is unconstrained, the prefix provides its
861 -- value and constraint, so add it to declaration.
863 if not Is_Constrained (Etype (Pref))
864 and then Is_Entity_Name (Pref)
865 then
866 Set_Expression (Decl, Pref);
867 Analyze (Decl);
869 -- Otherwise add an assignment statement to temporary using
870 -- prefix as RHS.
872 else
873 Analyze (Decl);
875 if No (Eval_Stmts) then
876 Eval_Stmts := New_List;
877 end if;
879 Append_To (Eval_Stmts,
880 Make_Assignment_Statement (Loc,
881 Name => New_Occurrence_Of (Temp, Loc),
882 Expression => Pref));
884 end if;
886 -- Ensure that the prefix is valid
888 if Validity_Checks_On and then Validity_Check_Operands then
889 Ensure_Valid (Pref);
890 end if;
892 -- Replace the original attribute 'Old by a reference to the
893 -- generated temporary.
895 Rewrite (N, New_Occurrence_Of (Temp, Loc));
897 -- Attribute 'Result
899 elsif Is_Attribute_Result (N) then
900 Rewrite (N, Make_Identifier (Loc, Name_uResult));
901 end if;
903 return OK;
904 end Expand_Attributes;
906 procedure Expand_Attributes_In is
907 new Traverse_Proc (Expand_Attributes);
909 -- Start of processing for Expand_Attributes_In_Consequence
911 begin
912 -- Inspect the consequence and expand any attribute 'Old and 'Result
913 -- references found within.
915 Expand_Attributes_In (Conseq);
917 -- The consequence does not contain any attribute 'Old references
919 if No (Eval_Stmts) then
920 return;
921 end if;
923 -- Augment the machinery to trigger the evaluation of all prefixes
924 -- found in the step above. If Eval is empty, then this is the first
925 -- consequence to yield expansion of 'Old. Generate:
927 -- if Flag then
928 -- <evaluation statements>
929 -- end if;
931 if No (Evals) then
932 Evals :=
933 Make_Implicit_If_Statement (CCs,
934 Condition => New_Occurrence_Of (Flag, Loc),
935 Then_Statements => Eval_Stmts);
937 -- Otherwise generate:
938 -- elsif Flag then
939 -- <evaluation statements>
940 -- end if;
942 else
943 if No (Elsif_Parts (Evals)) then
944 Set_Elsif_Parts (Evals, New_List);
945 end if;
947 Append_To (Elsif_Parts (Evals),
948 Make_Elsif_Part (Loc,
949 Condition => New_Occurrence_Of (Flag, Loc),
950 Then_Statements => Eval_Stmts));
951 end if;
952 end Expand_Attributes_In_Consequence;
954 ---------------
955 -- Increment --
956 ---------------
958 function Increment (Id : Entity_Id) return Node_Id is
959 begin
960 return
961 Make_Assignment_Statement (Loc,
962 Name => New_Occurrence_Of (Id, Loc),
963 Expression =>
964 Make_Op_Add (Loc,
965 Left_Opnd => New_Occurrence_Of (Id, Loc),
966 Right_Opnd => Make_Integer_Literal (Loc, 1)));
967 end Increment;
969 ---------
970 -- Set --
971 ---------
973 function Set (Id : Entity_Id) return Node_Id is
974 begin
975 return
976 Make_Assignment_Statement (Loc,
977 Name => New_Occurrence_Of (Id, Loc),
978 Expression => New_Occurrence_Of (Standard_True, Loc));
979 end Set;
981 -- Local variables
983 Aggr : constant Node_Id :=
984 Expression (First (Pragma_Argument_Associations (CCs)));
986 Case_Guard : Node_Id;
987 CG_Checks : Node_Id;
988 CG_Stmts : List_Id;
989 Conseq : Node_Id;
990 Conseq_Checks : Node_Id := Empty;
991 Count : Entity_Id;
992 Count_Decl : Node_Id;
993 Error_Decls : List_Id;
994 Flag : Entity_Id;
995 Flag_Decl : Node_Id;
996 If_Stmt : Node_Id;
997 Msg_Str : Entity_Id;
998 Multiple_PCs : Boolean;
999 Old_Evals : Node_Id := Empty;
1000 Others_Decl : Node_Id;
1001 Others_Flag : Entity_Id := Empty;
1002 Post_Case : Node_Id;
1004 -- Start of processing for Expand_Pragma_Contract_Cases
1006 begin
1007 -- Do nothing if pragma is not enabled. If pragma is disabled, it has
1008 -- already been rewritten as a Null statement.
1010 if Is_Ignored (CCs) then
1011 return;
1013 -- Guard against malformed contract cases
1015 elsif Nkind (Aggr) /= N_Aggregate then
1016 return;
1017 end if;
1019 -- The expansion of contract cases is quite distributed as it produces
1020 -- various statements to evaluate the case guards and consequences. To
1021 -- preserve the original context, set the Is_Assertion_Expr flag. This
1022 -- aids the Ghost legality checks when verifying the placement of a
1023 -- reference to a Ghost entity.
1025 In_Assertion_Expr := In_Assertion_Expr + 1;
1027 Multiple_PCs := List_Length (Component_Associations (Aggr)) > 1;
1029 -- Create the counter which tracks the number of case guards that
1030 -- evaluate to True.
1032 -- Count : Natural := 0;
1034 Count := Make_Temporary (Loc, 'C');
1035 Count_Decl :=
1036 Make_Object_Declaration (Loc,
1037 Defining_Identifier => Count,
1038 Object_Definition => New_Occurrence_Of (Standard_Natural, Loc),
1039 Expression => Make_Integer_Literal (Loc, 0));
1041 Prepend_To (Decls, Count_Decl);
1042 Analyze (Count_Decl);
1044 -- Create the base error message for multiple overlapping case guards
1046 -- Msg_Str : constant String :=
1047 -- "contract cases overlap for subprogram Subp_Id";
1049 if Multiple_PCs then
1050 Msg_Str := Make_Temporary (Loc, 'S');
1052 Start_String;
1053 Store_String_Chars ("contract cases overlap for subprogram ");
1054 Store_String_Chars (Get_Name_String (Chars (Subp_Id)));
1056 Error_Decls := New_List (
1057 Make_Object_Declaration (Loc,
1058 Defining_Identifier => Msg_Str,
1059 Constant_Present => True,
1060 Object_Definition => New_Occurrence_Of (Standard_String, Loc),
1061 Expression => Make_String_Literal (Loc, End_String)));
1062 end if;
1064 -- Process individual post cases
1066 Post_Case := First (Component_Associations (Aggr));
1067 while Present (Post_Case) loop
1068 Case_Guard := First (Choices (Post_Case));
1069 Conseq := Expression (Post_Case);
1071 -- The "others" choice requires special processing
1073 if Nkind (Case_Guard) = N_Others_Choice then
1074 Others_Flag := Make_Temporary (Loc, 'F');
1075 Others_Decl := Declaration_Of (Others_Flag);
1077 Prepend_To (Decls, Others_Decl);
1078 Analyze (Others_Decl);
1080 -- Check possible overlap between a case guard and "others"
1082 if Multiple_PCs and Exception_Extra_Info then
1083 Case_Guard_Error
1084 (Decls => Error_Decls,
1085 Flag => Others_Flag,
1086 Error_Loc => Sloc (Case_Guard),
1087 Msg => Msg_Str);
1088 end if;
1090 -- Inspect the consequence and perform special expansion of any
1091 -- attribute 'Old and 'Result references found within.
1093 Expand_Attributes_In_Consequence
1094 (Decls => Decls,
1095 Evals => Old_Evals,
1096 Flag => Others_Flag,
1097 Conseq => Conseq);
1099 -- Check the corresponding consequence of "others"
1101 Consequence_Error
1102 (Checks => Conseq_Checks,
1103 Flag => Others_Flag,
1104 Conseq => Conseq);
1106 -- Regular post case
1108 else
1109 -- Create the flag which tracks the state of its associated case
1110 -- guard.
1112 Flag := Make_Temporary (Loc, 'F');
1113 Flag_Decl := Declaration_Of (Flag);
1115 Prepend_To (Decls, Flag_Decl);
1116 Analyze (Flag_Decl);
1118 -- The flag is set when the case guard is evaluated to True
1119 -- if Case_Guard then
1120 -- Flag := True;
1121 -- Count := Count + 1;
1122 -- end if;
1124 If_Stmt :=
1125 Make_Implicit_If_Statement (CCs,
1126 Condition => Relocate_Node (Case_Guard),
1127 Then_Statements => New_List (
1128 Set (Flag),
1129 Increment (Count)));
1131 Append_To (Decls, If_Stmt);
1132 Analyze (If_Stmt);
1134 -- Check whether this case guard overlaps with another one
1136 if Multiple_PCs and Exception_Extra_Info then
1137 Case_Guard_Error
1138 (Decls => Error_Decls,
1139 Flag => Flag,
1140 Error_Loc => Sloc (Case_Guard),
1141 Msg => Msg_Str);
1142 end if;
1144 -- Inspect the consequence and perform special expansion of any
1145 -- attribute 'Old and 'Result references found within.
1147 Expand_Attributes_In_Consequence
1148 (Decls => Decls,
1149 Evals => Old_Evals,
1150 Flag => Flag,
1151 Conseq => Conseq);
1153 -- The corresponding consequence of the case guard which evaluated
1154 -- to True must hold on exit from the subprogram.
1156 Consequence_Error
1157 (Checks => Conseq_Checks,
1158 Flag => Flag,
1159 Conseq => Conseq);
1160 end if;
1162 Next (Post_Case);
1163 end loop;
1165 -- Raise Assertion_Error when none of the case guards evaluate to True.
1166 -- The only exception is when we have "others", in which case there is
1167 -- no error because "others" acts as a default True.
1169 -- Generate:
1170 -- Flag := True;
1172 if Present (Others_Flag) then
1173 CG_Stmts := New_List (Set (Others_Flag));
1175 -- Generate:
1176 -- raise Assertion_Error with "xxx contract cases incomplete";
1178 else
1179 Start_String;
1180 Store_String_Chars (Build_Location_String (Loc));
1181 Store_String_Chars (" contract cases incomplete");
1183 CG_Stmts := New_List (
1184 Make_Procedure_Call_Statement (Loc,
1185 Name =>
1186 New_Occurrence_Of (RTE (RE_Raise_Assert_Failure), Loc),
1187 Parameter_Associations => New_List (
1188 Make_String_Literal (Loc, End_String))));
1189 end if;
1191 CG_Checks :=
1192 Make_Implicit_If_Statement (CCs,
1193 Condition =>
1194 Make_Op_Eq (Loc,
1195 Left_Opnd => New_Occurrence_Of (Count, Loc),
1196 Right_Opnd => Make_Integer_Literal (Loc, 0)),
1197 Then_Statements => CG_Stmts);
1199 -- Detect a possible failure due to several case guards evaluating to
1200 -- True.
1202 -- Generate:
1203 -- elsif Count > 0 then
1204 -- declare
1205 -- <Error_Decls>
1206 -- begin
1207 -- raise Assertion_Error with <Msg_Str>;
1208 -- end if;
1210 if Multiple_PCs then
1211 Set_Elsif_Parts (CG_Checks, New_List (
1212 Make_Elsif_Part (Loc,
1213 Condition =>
1214 Make_Op_Gt (Loc,
1215 Left_Opnd => New_Occurrence_Of (Count, Loc),
1216 Right_Opnd => Make_Integer_Literal (Loc, 1)),
1218 Then_Statements => New_List (
1219 Make_Block_Statement (Loc,
1220 Declarations => Error_Decls,
1221 Handled_Statement_Sequence =>
1222 Make_Handled_Sequence_Of_Statements (Loc,
1223 Statements => New_List (
1224 Make_Procedure_Call_Statement (Loc,
1225 Name =>
1226 New_Occurrence_Of
1227 (RTE (RE_Raise_Assert_Failure), Loc),
1228 Parameter_Associations => New_List (
1229 New_Occurrence_Of (Msg_Str, Loc))))))))));
1230 end if;
1232 Append_To (Decls, CG_Checks);
1233 Analyze (CG_Checks);
1235 -- Once all case guards are evaluated and checked, evaluate any prefixes
1236 -- of attribute 'Old founds in the selected consequence.
1238 if Present (Old_Evals) then
1239 Append_To (Decls, Old_Evals);
1240 Analyze (Old_Evals);
1241 end if;
1243 -- Raise Assertion_Error when the corresponding consequence of a case
1244 -- guard that evaluated to True fails.
1246 if No (Stmts) then
1247 Stmts := New_List;
1248 end if;
1250 Append_To (Stmts, Conseq_Checks);
1252 In_Assertion_Expr := In_Assertion_Expr - 1;
1253 end Expand_Pragma_Contract_Cases;
1255 ---------------------------------------
1256 -- Expand_Pragma_Import_Or_Interface --
1257 ---------------------------------------
1259 procedure Expand_Pragma_Import_Or_Interface (N : Node_Id) is
1260 Def_Id : Entity_Id;
1262 begin
1263 -- In Relaxed_RM_Semantics, support old Ada 83 style:
1264 -- pragma Import (Entity, "external name");
1266 if Relaxed_RM_Semantics
1267 and then List_Length (Pragma_Argument_Associations (N)) = 2
1268 and then Pragma_Name (N) = Name_Import
1269 and then Nkind (Arg2 (N)) = N_String_Literal
1270 then
1271 Def_Id := Entity (Arg1 (N));
1272 else
1273 Def_Id := Entity (Arg2 (N));
1274 end if;
1276 -- Variable case (we have to undo any initialization already done)
1278 if Ekind (Def_Id) = E_Variable then
1279 Undo_Initialization (Def_Id, N);
1281 -- Case of exception with convention C++
1283 elsif Ekind (Def_Id) = E_Exception
1284 and then Convention (Def_Id) = Convention_CPP
1285 then
1286 -- Import a C++ convention
1288 declare
1289 Loc : constant Source_Ptr := Sloc (N);
1290 Rtti_Name : constant Node_Id := Arg3 (N);
1291 Dum : constant Entity_Id := Make_Temporary (Loc, 'D');
1292 Exdata : List_Id;
1293 Lang_Char : Node_Id;
1294 Foreign_Data : Node_Id;
1296 begin
1297 Exdata := Component_Associations (Expression (Parent (Def_Id)));
1299 Lang_Char := Next (First (Exdata));
1301 -- Change the one-character language designator to 'C'
1303 Rewrite (Expression (Lang_Char),
1304 Make_Character_Literal (Loc,
1305 Chars => Name_uC,
1306 Char_Literal_Value => UI_From_Int (Character'Pos ('C'))));
1307 Analyze (Expression (Lang_Char));
1309 -- Change the value of Foreign_Data
1311 Foreign_Data := Next (Next (Next (Next (Lang_Char))));
1313 Insert_Actions (Def_Id, New_List (
1314 Make_Object_Declaration (Loc,
1315 Defining_Identifier => Dum,
1316 Object_Definition =>
1317 New_Occurrence_Of (Standard_Character, Loc)),
1319 Make_Pragma (Loc,
1320 Chars => Name_Import,
1321 Pragma_Argument_Associations => New_List (
1322 Make_Pragma_Argument_Association (Loc,
1323 Expression => Make_Identifier (Loc, Name_Ada)),
1325 Make_Pragma_Argument_Association (Loc,
1326 Expression => Make_Identifier (Loc, Chars (Dum))),
1328 Make_Pragma_Argument_Association (Loc,
1329 Chars => Name_External_Name,
1330 Expression => Relocate_Node (Rtti_Name))))));
1332 Rewrite (Expression (Foreign_Data),
1333 Unchecked_Convert_To (Standard_A_Char,
1334 Make_Attribute_Reference (Loc,
1335 Prefix => Make_Identifier (Loc, Chars (Dum)),
1336 Attribute_Name => Name_Address)));
1337 Analyze (Expression (Foreign_Data));
1338 end;
1340 -- No special expansion required for any other case
1342 else
1343 null;
1344 end if;
1345 end Expand_Pragma_Import_Or_Interface;
1347 -------------------------------------
1348 -- Expand_Pragma_Initial_Condition --
1349 -------------------------------------
1351 procedure Expand_Pragma_Initial_Condition (Spec_Or_Body : Node_Id) is
1352 Loc : constant Source_Ptr := Sloc (Spec_Or_Body);
1354 Check : Node_Id;
1355 Expr : Node_Id;
1356 Init_Cond : Node_Id;
1357 List : List_Id;
1358 Pack_Id : Entity_Id;
1360 begin
1361 if Nkind (Spec_Or_Body) = N_Package_Body then
1362 Pack_Id := Corresponding_Spec (Spec_Or_Body);
1364 if Present (Handled_Statement_Sequence (Spec_Or_Body)) then
1365 List := Statements (Handled_Statement_Sequence (Spec_Or_Body));
1367 -- The package body lacks statements, create an empty list
1369 else
1370 List := New_List;
1372 Set_Handled_Statement_Sequence (Spec_Or_Body,
1373 Make_Handled_Sequence_Of_Statements (Loc, Statements => List));
1374 end if;
1376 elsif Nkind (Spec_Or_Body) = N_Package_Declaration then
1377 Pack_Id := Defining_Entity (Spec_Or_Body);
1379 if Present (Visible_Declarations (Specification (Spec_Or_Body))) then
1380 List := Visible_Declarations (Specification (Spec_Or_Body));
1382 -- The package lacks visible declarations, create an empty list
1384 else
1385 List := New_List;
1387 Set_Visible_Declarations (Specification (Spec_Or_Body), List);
1388 end if;
1390 -- This routine should not be used on anything other than packages
1392 else
1393 raise Program_Error;
1394 end if;
1396 Init_Cond := Get_Pragma (Pack_Id, Pragma_Initial_Condition);
1398 -- The caller should check whether the package is subject to pragma
1399 -- Initial_Condition.
1401 pragma Assert (Present (Init_Cond));
1403 Expr :=
1404 Get_Pragma_Arg (First (Pragma_Argument_Associations (Init_Cond)));
1406 -- The assertion expression was found to be illegal, do not generate the
1407 -- runtime check as it will repeat the illegality.
1409 if Error_Posted (Init_Cond) or else Error_Posted (Expr) then
1410 return;
1411 end if;
1413 -- Generate:
1414 -- pragma Check (Initial_Condition, <Expr>);
1416 Check :=
1417 Make_Pragma (Loc,
1418 Chars => Name_Check,
1419 Pragma_Argument_Associations => New_List (
1420 Make_Pragma_Argument_Association (Loc,
1421 Expression => Make_Identifier (Loc, Name_Initial_Condition)),
1422 Make_Pragma_Argument_Association (Loc,
1423 Expression => New_Copy_Tree (Expr))));
1425 Append_To (List, Check);
1426 Analyze (Check);
1427 end Expand_Pragma_Initial_Condition;
1429 ------------------------------------
1430 -- Expand_Pragma_Inspection_Point --
1431 ------------------------------------
1433 -- If no argument is given, then we supply a default argument list that
1434 -- includes all objects declared at the source level in all subprograms
1435 -- that enclose the inspection point pragma.
1437 procedure Expand_Pragma_Inspection_Point (N : Node_Id) is
1438 Loc : constant Source_Ptr := Sloc (N);
1439 A : List_Id;
1440 Assoc : Node_Id;
1441 S : Entity_Id;
1442 E : Entity_Id;
1444 begin
1445 if No (Pragma_Argument_Associations (N)) then
1446 A := New_List;
1447 S := Current_Scope;
1449 while S /= Standard_Standard loop
1450 E := First_Entity (S);
1451 while Present (E) loop
1452 if Comes_From_Source (E)
1453 and then Is_Object (E)
1454 and then not Is_Entry_Formal (E)
1455 and then Ekind (E) /= E_Component
1456 and then Ekind (E) /= E_Discriminant
1457 and then Ekind (E) /= E_Generic_In_Parameter
1458 and then Ekind (E) /= E_Generic_In_Out_Parameter
1459 then
1460 Append_To (A,
1461 Make_Pragma_Argument_Association (Loc,
1462 Expression => New_Occurrence_Of (E, Loc)));
1463 end if;
1465 Next_Entity (E);
1466 end loop;
1468 S := Scope (S);
1469 end loop;
1471 Set_Pragma_Argument_Associations (N, A);
1472 end if;
1474 -- Expand the arguments of the pragma. Expanding an entity reference
1475 -- is a noop, except in a protected operation, where a reference may
1476 -- have to be transformed into a reference to the corresponding prival.
1477 -- Are there other pragmas that may require this ???
1479 Assoc := First (Pragma_Argument_Associations (N));
1480 while Present (Assoc) loop
1481 Expand (Expression (Assoc));
1482 Next (Assoc);
1483 end loop;
1484 end Expand_Pragma_Inspection_Point;
1486 --------------------------------------
1487 -- Expand_Pragma_Interrupt_Priority --
1488 --------------------------------------
1490 -- Supply default argument if none exists (System.Interrupt_Priority'Last)
1492 procedure Expand_Pragma_Interrupt_Priority (N : Node_Id) is
1493 Loc : constant Source_Ptr := Sloc (N);
1494 begin
1495 if No (Pragma_Argument_Associations (N)) then
1496 Set_Pragma_Argument_Associations (N, New_List (
1497 Make_Pragma_Argument_Association (Loc,
1498 Expression =>
1499 Make_Attribute_Reference (Loc,
1500 Prefix =>
1501 New_Occurrence_Of (RTE (RE_Interrupt_Priority), Loc),
1502 Attribute_Name => Name_Last))));
1503 end if;
1504 end Expand_Pragma_Interrupt_Priority;
1506 --------------------------------
1507 -- Expand_Pragma_Loop_Variant --
1508 --------------------------------
1510 -- Pragma Loop_Variant is expanded in the following manner:
1512 -- Original code
1514 -- for | while ... loop
1515 -- <preceding source statements>
1516 -- pragma Loop_Variant
1517 -- (Increases => Incr_Expr,
1518 -- Decreases => Decr_Expr);
1519 -- <succeeding source statements>
1520 -- end loop;
1522 -- Expanded code
1524 -- Curr_1 : <type of Incr_Expr>;
1525 -- Curr_2 : <type of Decr_Expr>;
1526 -- Old_1 : <type of Incr_Expr>;
1527 -- Old_2 : <type of Decr_Expr>;
1528 -- Flag : Boolean := False;
1530 -- for | while ... loop
1531 -- <preceding source statements>
1533 -- if Flag then
1534 -- Old_1 := Curr_1;
1535 -- Old_2 := Curr_2;
1536 -- end if;
1538 -- Curr_1 := <Incr_Expr>;
1539 -- Curr_2 := <Decr_Expr>;
1541 -- if Flag then
1542 -- if Curr_1 /= Old_1 then
1543 -- pragma Check (Loop_Variant, Curr_1 > Old_1);
1544 -- else
1545 -- pragma Check (Loop_Variant, Curr_2 < Old_2);
1546 -- end if;
1547 -- else
1548 -- Flag := True;
1549 -- end if;
1551 -- <succeeding source statements>
1552 -- end loop;
1554 procedure Expand_Pragma_Loop_Variant (N : Node_Id) is
1555 Loc : constant Source_Ptr := Sloc (N);
1556 Last_Var : constant Node_Id :=
1557 Last (Pragma_Argument_Associations (N));
1559 Curr_Assign : List_Id := No_List;
1560 Flag_Id : Entity_Id := Empty;
1561 If_Stmt : Node_Id := Empty;
1562 Old_Assign : List_Id := No_List;
1563 Loop_Scop : Entity_Id;
1564 Loop_Stmt : Node_Id;
1565 Variant : Node_Id;
1567 procedure Process_Variant (Variant : Node_Id; Is_Last : Boolean);
1568 -- Process a single increasing / decreasing termination variant. Flag
1569 -- Is_Last should be set when processing the last variant.
1571 ---------------------
1572 -- Process_Variant --
1573 ---------------------
1575 procedure Process_Variant (Variant : Node_Id; Is_Last : Boolean) is
1576 function Make_Op
1577 (Loc : Source_Ptr;
1578 Curr_Val : Node_Id;
1579 Old_Val : Node_Id) return Node_Id;
1580 -- Generate a comparison between Curr_Val and Old_Val depending on
1581 -- the change mode (Increases / Decreases) of the variant.
1583 -------------
1584 -- Make_Op --
1585 -------------
1587 function Make_Op
1588 (Loc : Source_Ptr;
1589 Curr_Val : Node_Id;
1590 Old_Val : Node_Id) return Node_Id
1592 begin
1593 if Chars (Variant) = Name_Increases then
1594 return Make_Op_Gt (Loc, Curr_Val, Old_Val);
1595 else pragma Assert (Chars (Variant) = Name_Decreases);
1596 return Make_Op_Lt (Loc, Curr_Val, Old_Val);
1597 end if;
1598 end Make_Op;
1600 -- Local variables
1602 Expr : constant Node_Id := Expression (Variant);
1603 Expr_Typ : constant Entity_Id := Etype (Expr);
1604 Loc : constant Source_Ptr := Sloc (Expr);
1605 Loop_Loc : constant Source_Ptr := Sloc (Loop_Stmt);
1606 Curr_Id : Entity_Id;
1607 Old_Id : Entity_Id;
1608 Prag : Node_Id;
1610 -- Start of processing for Process_Variant
1612 begin
1613 -- All temporaries generated in this routine must be inserted before
1614 -- the related loop statement. Ensure that the proper scope is on the
1615 -- stack when analyzing the temporaries. Note that we also use the
1616 -- Sloc of the related loop.
1618 Push_Scope (Scope (Loop_Scop));
1620 -- Step 1: Create the declaration of the flag which controls the
1621 -- behavior of the assertion on the first iteration of the loop.
1623 if No (Flag_Id) then
1625 -- Generate:
1626 -- Flag : Boolean := False;
1628 Flag_Id := Make_Temporary (Loop_Loc, 'F');
1630 Insert_Action (Loop_Stmt,
1631 Make_Object_Declaration (Loop_Loc,
1632 Defining_Identifier => Flag_Id,
1633 Object_Definition =>
1634 New_Occurrence_Of (Standard_Boolean, Loop_Loc),
1635 Expression =>
1636 New_Occurrence_Of (Standard_False, Loop_Loc)));
1638 -- Prevent an unwanted optimization where the Current_Value of
1639 -- the flag eliminates the if statement which stores the variant
1640 -- values coming from the previous iteration.
1642 -- Flag : Boolean := False;
1643 -- loop
1644 -- if Flag then -- condition rewritten to False
1645 -- Old_N := Curr_N; -- and if statement eliminated
1646 -- end if;
1647 -- . . .
1648 -- Flag := True;
1649 -- end loop;
1651 Set_Current_Value (Flag_Id, Empty);
1652 end if;
1654 -- Step 2: Create the temporaries which store the old and current
1655 -- values of the associated expression.
1657 -- Generate:
1658 -- Curr : <type of Expr>;
1660 Curr_Id := Make_Temporary (Loc, 'C');
1662 Insert_Action (Loop_Stmt,
1663 Make_Object_Declaration (Loop_Loc,
1664 Defining_Identifier => Curr_Id,
1665 Object_Definition => New_Occurrence_Of (Expr_Typ, Loop_Loc)));
1667 -- Generate:
1668 -- Old : <type of Expr>;
1670 Old_Id := Make_Temporary (Loc, 'P');
1672 Insert_Action (Loop_Stmt,
1673 Make_Object_Declaration (Loop_Loc,
1674 Defining_Identifier => Old_Id,
1675 Object_Definition => New_Occurrence_Of (Expr_Typ, Loop_Loc)));
1677 -- Restore original scope after all temporaries have been analyzed
1679 Pop_Scope;
1681 -- Step 3: Store value of the expression from the previous iteration
1683 if No (Old_Assign) then
1684 Old_Assign := New_List;
1685 end if;
1687 -- Generate:
1688 -- Old := Curr;
1690 Append_To (Old_Assign,
1691 Make_Assignment_Statement (Loc,
1692 Name => New_Occurrence_Of (Old_Id, Loc),
1693 Expression => New_Occurrence_Of (Curr_Id, Loc)));
1695 -- Step 4: Store the current value of the expression
1697 if No (Curr_Assign) then
1698 Curr_Assign := New_List;
1699 end if;
1701 -- Generate:
1702 -- Curr := <Expr>;
1704 Append_To (Curr_Assign,
1705 Make_Assignment_Statement (Loc,
1706 Name => New_Occurrence_Of (Curr_Id, Loc),
1707 Expression => Relocate_Node (Expr)));
1709 -- Step 5: Create corresponding assertion to verify change of value
1711 -- Generate:
1712 -- pragma Check (Loop_Variant, Curr <|> Old);
1714 Prag :=
1715 Make_Pragma (Loc,
1716 Chars => Name_Check,
1717 Pragma_Argument_Associations => New_List (
1718 Make_Pragma_Argument_Association (Loc,
1719 Expression => Make_Identifier (Loc, Name_Loop_Variant)),
1720 Make_Pragma_Argument_Association (Loc,
1721 Expression =>
1722 Make_Op (Loc,
1723 Curr_Val => New_Occurrence_Of (Curr_Id, Loc),
1724 Old_Val => New_Occurrence_Of (Old_Id, Loc)))));
1726 -- Generate:
1727 -- if Curr /= Old then
1728 -- <Prag>;
1730 if No (If_Stmt) then
1732 -- When there is just one termination variant, do not compare the
1733 -- old and current value for equality, just check the pragma.
1735 if Is_Last then
1736 If_Stmt := Prag;
1737 else
1738 If_Stmt :=
1739 Make_If_Statement (Loc,
1740 Condition =>
1741 Make_Op_Ne (Loc,
1742 Left_Opnd => New_Occurrence_Of (Curr_Id, Loc),
1743 Right_Opnd => New_Occurrence_Of (Old_Id, Loc)),
1744 Then_Statements => New_List (Prag));
1745 end if;
1747 -- Generate:
1748 -- else
1749 -- <Prag>;
1750 -- end if;
1752 elsif Is_Last then
1753 Set_Else_Statements (If_Stmt, New_List (Prag));
1755 -- Generate:
1756 -- elsif Curr /= Old then
1757 -- <Prag>;
1759 else
1760 if Elsif_Parts (If_Stmt) = No_List then
1761 Set_Elsif_Parts (If_Stmt, New_List);
1762 end if;
1764 Append_To (Elsif_Parts (If_Stmt),
1765 Make_Elsif_Part (Loc,
1766 Condition =>
1767 Make_Op_Ne (Loc,
1768 Left_Opnd => New_Occurrence_Of (Curr_Id, Loc),
1769 Right_Opnd => New_Occurrence_Of (Old_Id, Loc)),
1770 Then_Statements => New_List (Prag)));
1771 end if;
1772 end Process_Variant;
1774 -- Start of processing for Expand_Pragma_Loop_Variant
1776 begin
1777 -- If pragma is not enabled, rewrite as Null statement. If pragma is
1778 -- disabled, it has already been rewritten as a Null statement.
1780 if Is_Ignored (N) then
1781 Rewrite (N, Make_Null_Statement (Loc));
1782 Analyze (N);
1783 return;
1784 end if;
1786 -- The expansion of Loop_Variant is quite distributed as it produces
1787 -- various statements to capture and compare the arguments. To preserve
1788 -- the original context, set the Is_Assertion_Expr flag. This aids the
1789 -- Ghost legality checks when verifying the placement of a reference to
1790 -- a Ghost entity.
1792 In_Assertion_Expr := In_Assertion_Expr + 1;
1794 -- Locate the enclosing loop for which this assertion applies. In the
1795 -- case of Ada 2012 array iteration, we might be dealing with nested
1796 -- loops. Only the outermost loop has an identifier.
1798 Loop_Stmt := N;
1799 while Present (Loop_Stmt) loop
1800 if Nkind (Loop_Stmt) = N_Loop_Statement
1801 and then Present (Identifier (Loop_Stmt))
1802 then
1803 exit;
1804 end if;
1806 Loop_Stmt := Parent (Loop_Stmt);
1807 end loop;
1809 Loop_Scop := Entity (Identifier (Loop_Stmt));
1811 -- Create the circuitry which verifies individual variants
1813 Variant := First (Pragma_Argument_Associations (N));
1814 while Present (Variant) loop
1815 Process_Variant (Variant, Is_Last => Variant = Last_Var);
1816 Next (Variant);
1817 end loop;
1819 -- Construct the segment which stores the old values of all expressions.
1820 -- Generate:
1821 -- if Flag then
1822 -- <Old_Assign>
1823 -- end if;
1825 Insert_Action (N,
1826 Make_If_Statement (Loc,
1827 Condition => New_Occurrence_Of (Flag_Id, Loc),
1828 Then_Statements => Old_Assign));
1830 -- Update the values of all expressions
1832 Insert_Actions (N, Curr_Assign);
1834 -- Add the assertion circuitry to test all changes in expressions.
1835 -- Generate:
1836 -- if Flag then
1837 -- <If_Stmt>
1838 -- else
1839 -- Flag := True;
1840 -- end if;
1842 Insert_Action (N,
1843 Make_If_Statement (Loc,
1844 Condition => New_Occurrence_Of (Flag_Id, Loc),
1845 Then_Statements => New_List (If_Stmt),
1846 Else_Statements => New_List (
1847 Make_Assignment_Statement (Loc,
1848 Name => New_Occurrence_Of (Flag_Id, Loc),
1849 Expression => New_Occurrence_Of (Standard_True, Loc)))));
1851 -- Note: the pragma has been completely transformed into a sequence of
1852 -- corresponding declarations and statements. We leave it in the tree
1853 -- for documentation purposes. It will be ignored by the backend.
1855 In_Assertion_Expr := In_Assertion_Expr - 1;
1856 end Expand_Pragma_Loop_Variant;
1858 --------------------------------
1859 -- Expand_Pragma_Psect_Object --
1860 --------------------------------
1862 -- Convert to Common_Object, and expand the resulting pragma
1864 procedure Expand_Pragma_Psect_Object (N : Node_Id)
1865 renames Expand_Pragma_Common_Object;
1867 -------------------------------------
1868 -- Expand_Pragma_Relative_Deadline --
1869 -------------------------------------
1871 procedure Expand_Pragma_Relative_Deadline (N : Node_Id) is
1872 P : constant Node_Id := Parent (N);
1873 Loc : constant Source_Ptr := Sloc (N);
1875 begin
1876 -- Expand the pragma only in the case of the main subprogram. For tasks
1877 -- the expansion is done in exp_ch9. Generate a call to Set_Deadline
1878 -- at Clock plus the relative deadline specified in the pragma. Time
1879 -- values are translated into Duration to allow for non-private
1880 -- addition operation.
1882 if Nkind (P) = N_Subprogram_Body then
1883 Rewrite
1885 Make_Procedure_Call_Statement (Loc,
1886 Name => New_Occurrence_Of (RTE (RE_Set_Deadline), Loc),
1887 Parameter_Associations => New_List (
1888 Unchecked_Convert_To (RTE (RO_RT_Time),
1889 Make_Op_Add (Loc,
1890 Left_Opnd =>
1891 Make_Function_Call (Loc,
1892 New_Occurrence_Of (RTE (RO_RT_To_Duration), Loc),
1893 New_List
1894 (Make_Function_Call
1895 (Loc, New_Occurrence_Of (RTE (RE_Clock), Loc)))),
1896 Right_Opnd =>
1897 Unchecked_Convert_To (Standard_Duration, Arg1 (N)))))));
1899 Analyze (N);
1900 end if;
1901 end Expand_Pragma_Relative_Deadline;
1903 -------------------------------------------
1904 -- Expand_Pragma_Suppress_Initialization --
1905 -------------------------------------------
1907 procedure Expand_Pragma_Suppress_Initialization (N : Node_Id) is
1908 Def_Id : constant Entity_Id := Entity (Arg1 (N));
1910 begin
1911 -- Variable case (we have to undo any initialization already done)
1913 if Ekind (Def_Id) = E_Variable then
1914 Undo_Initialization (Def_Id, N);
1915 end if;
1916 end Expand_Pragma_Suppress_Initialization;
1918 -------------------------
1919 -- Undo_Initialization --
1920 -------------------------
1922 procedure Undo_Initialization (Def_Id : Entity_Id; N : Node_Id) is
1923 Init_Call : Node_Id;
1925 begin
1926 -- When applied to a variable, the default initialization must not be
1927 -- done. As it is already done when the pragma is found, we just get rid
1928 -- of the call the initialization procedure which followed the object
1929 -- declaration. The call is inserted after the declaration, but validity
1930 -- checks may also have been inserted and thus the initialization call
1931 -- does not necessarily appear immediately after the object declaration.
1933 -- We can't use the freezing mechanism for this purpose, since we have
1934 -- to elaborate the initialization expression when it is first seen (so
1935 -- this elaboration cannot be deferred to the freeze point).
1937 -- Find and remove generated initialization call for object, if any
1939 Init_Call := Remove_Init_Call (Def_Id, Rep_Clause => N);
1941 -- Any default initialization expression should be removed (e.g.
1942 -- null defaults for access objects, zero initialization of packed
1943 -- bit arrays). Imported objects aren't allowed to have explicit
1944 -- initialization, so the expression must have been generated by
1945 -- the compiler.
1947 if No (Init_Call) and then Present (Expression (Parent (Def_Id))) then
1948 Set_Expression (Parent (Def_Id), Empty);
1949 end if;
1951 -- The object may not have any initialization, but in the presence of
1952 -- Initialize_Scalars code is inserted after then declaration, which
1953 -- must now be removed as well. The code carries the same source
1954 -- location as the declaration itself.
1956 if Initialize_Scalars and then Is_Array_Type (Etype (Def_Id)) then
1957 declare
1958 Init : Node_Id;
1959 Nxt : Node_Id;
1960 begin
1961 Init := Next (Parent (Def_Id));
1962 while not Comes_From_Source (Init)
1963 and then Sloc (Init) = Sloc (Def_Id)
1964 loop
1965 Nxt := Next (Init);
1966 Remove (Init);
1967 Init := Nxt;
1968 end loop;
1969 end;
1970 end if;
1971 end Undo_Initialization;
1973 end Exp_Prag;