1 ------------------------------------------------------------------------------
3 -- GNAT COMPILER COMPONENTS --
9 -- Copyright (C) 1992-2013, Free Software Foundation, Inc. --
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. --
21 -- GNAT was originally developed by the GNAT team at New York University. --
22 -- Extensive contributions were provided by Ada Core Technologies Inc. --
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 Namet
; use Namet
;
36 with Nlists
; use Nlists
;
37 with Nmake
; use Nmake
;
39 with Restrict
; use Restrict
;
40 with Rident
; use Rident
;
41 with Rtsfind
; use Rtsfind
;
43 with Sem_Ch8
; use Sem_Ch8
;
44 with Sem_Res
; use Sem_Res
;
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 Targparm
; use Targparm
;
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_Import_Export_Exception
(N
: Node_Id
);
72 procedure Expand_Pragma_Inspection_Point
(N
: Node_Id
);
73 procedure Expand_Pragma_Interrupt_Priority
(N
: Node_Id
);
74 procedure Expand_Pragma_Loop_Variant
(N
: Node_Id
);
75 procedure Expand_Pragma_Psect_Object
(N
: Node_Id
);
76 procedure Expand_Pragma_Relative_Deadline
(N
: Node_Id
);
82 function Arg1
(N
: Node_Id
) return Node_Id
is
83 Arg
: constant Node_Id
:= First
(Pragma_Argument_Associations
(N
));
86 and then Nkind
(Arg
) = N_Pragma_Argument_Association
88 return Expression
(Arg
);
98 function Arg2
(N
: Node_Id
) return Node_Id
is
99 Arg1
: constant Node_Id
:= First
(Pragma_Argument_Associations
(N
));
107 Arg
: constant Node_Id
:= Next
(Arg1
);
110 and then Nkind
(Arg
) = N_Pragma_Argument_Association
112 return Expression
(Arg
);
124 function Arg3
(N
: Node_Id
) return Node_Id
is
125 Arg1
: constant Node_Id
:= First
(Pragma_Argument_Associations
(N
));
133 Arg
: Node_Id
:= Next
(Arg1
);
142 and then Nkind
(Arg
) = N_Pragma_Argument_Association
144 return Expression
(Arg
);
153 ---------------------------
154 -- Expand_Contract_Cases --
155 ---------------------------
157 -- Pragma Contract_Cases is expanded in the following manner:
160 -- Count : Natural := 0;
161 -- Flag_1 : Boolean := False;
163 -- Flag_N : Boolean := False;
164 -- Flag_N+1 : Boolean := False; -- when "others" present
169 -- <preconditions (if any)>
171 -- -- Evaluate all case guards
173 -- if Case_Guard_1 then
175 -- Count := Count + 1;
178 -- if Case_Guard_N then
180 -- Count := Count + 1;
183 -- -- Emit errors depending on the number of case guards that
184 -- -- evaluated to True.
187 -- raise Assertion_Error with "xxx contract cases incomplete";
189 -- Flag_N+1 := True; -- when "others" present
191 -- elsif Count > 1 then
193 -- Str0 : constant String :=
194 -- "contract cases overlap for subprogram ABC";
195 -- Str1 : constant String :=
197 -- Str0 & "case guard at xxx evaluates to True"
199 -- StrN : constant String :=
201 -- StrN-1 & "case guard at xxx evaluates to True"
204 -- raise Assertion_Error with StrN;
208 -- -- Evaluate all attribute 'Old prefixes found in the selected
212 -- Pref_1 := <prefix of 'Old found in Consequence_1>
215 -- Pref_M := <prefix of 'Old found in Consequence_N>
218 -- procedure _Postconditions is
220 -- <postconditions (if any)>
222 -- if Flag_1 and then not Consequence_1 then
223 -- raise Assertion_Error with "failed contract case at xxx";
226 -- if Flag_N[+1] and then not Consequence_N[+1] then
227 -- raise Assertion_Error with "failed contract case at xxx";
229 -- end _Postconditions;
234 procedure Expand_Contract_Cases
238 Stmts
: in out List_Id
)
240 Loc
: constant Source_Ptr
:= Sloc
(CCs
);
242 procedure Case_Guard_Error
245 Error_Loc
: Source_Ptr
;
246 Msg
: in out Entity_Id
);
247 -- Given a declarative list Decls, status flag Flag, the location of the
248 -- error and a string Msg, construct the following check:
249 -- Msg : constant String :=
251 -- Msg & "case guard at Error_Loc evaluates to True"
253 -- The resulting code is added to Decls
255 procedure Consequence_Error
256 (Checks
: in out Node_Id
;
259 -- Given an if statement Checks, status flag Flag and a consequence
260 -- Conseq, construct the following check:
261 -- [els]if Flag and then not Conseq then
262 -- raise Assertion_Error
263 -- with "failed contract case at Sloc (Conseq)";
265 -- The resulting code is added to Checks
267 function Declaration_Of
(Id
: Entity_Id
) return Node_Id
;
268 -- Given the entity Id of a boolean flag, generate:
269 -- Id : Boolean := False;
271 procedure Expand_Old_In_Consequence
273 Evals
: in out Node_Id
;
276 -- Perform specialized expansion of all attribute 'Old references found
277 -- in consequence Conseq such that at runtime only prefixes coming from
278 -- the selected consequence are evaluated. Any temporaries generated in
279 -- the process are added to declarative list Decls. Evals is a complex
280 -- if statement tasked with the evaluation of all prefixes coming from
281 -- a selected consequence. Flag is the corresponding case guard flag.
282 -- Conseq is the consequence expression.
284 function Increment
(Id
: Entity_Id
) return Node_Id
;
285 -- Given the entity Id of a numerical variable, generate:
288 function Set
(Id
: Entity_Id
) return Node_Id
;
289 -- Given the entity Id of a boolean variable, generate:
292 ----------------------
293 -- Case_Guard_Error --
294 ----------------------
296 procedure Case_Guard_Error
299 Error_Loc
: Source_Ptr
;
300 Msg
: in out Entity_Id
)
302 New_Line
: constant Character := Character'Val (10);
303 New_Msg
: constant Entity_Id
:= Make_Temporary
(Loc
, 'S');
307 Store_String_Char
(New_Line
);
308 Store_String_Chars
(" case guard at ");
309 Store_String_Chars
(Build_Location_String
(Error_Loc
));
310 Store_String_Chars
(" evaluates to True");
313 -- New_Msg : constant String :=
315 -- Msg & "case guard at Error_Loc evaluates to True"
319 Make_Object_Declaration
(Loc
,
320 Defining_Identifier
=> New_Msg
,
321 Constant_Present
=> True,
322 Object_Definition
=> New_Occurrence_Of
(Standard_String
, Loc
),
324 Make_If_Expression
(Loc
,
325 Expressions
=> New_List
(
326 New_Occurrence_Of
(Flag
, Loc
),
329 Left_Opnd
=> New_Occurrence_Of
(Msg
, Loc
),
330 Right_Opnd
=> Make_String_Literal
(Loc
, End_String
)),
332 New_Occurrence_Of
(Msg
, Loc
)))));
335 end Case_Guard_Error
;
337 -----------------------
338 -- Consequence_Error --
339 -----------------------
341 procedure Consequence_Error
342 (Checks
: in out Node_Id
;
351 -- Flag and then not Conseq
355 Left_Opnd
=> New_Occurrence_Of
(Flag
, Loc
),
358 Right_Opnd
=> Relocate_Node
(Conseq
)));
361 -- raise Assertion_Error
362 -- with "failed contract case at Sloc (Conseq)";
365 Store_String_Chars
("failed contract case at ");
366 Store_String_Chars
(Build_Location_String
(Sloc
(Conseq
)));
369 Make_Procedure_Call_Statement
(Loc
,
371 New_Occurrence_Of
(RTE
(RE_Raise_Assert_Failure
), Loc
),
372 Parameter_Associations
=> New_List
(
373 Make_String_Literal
(Loc
, End_String
)));
377 Make_Implicit_If_Statement
(CCs
,
379 Then_Statements
=> New_List
(Error
));
382 if No
(Elsif_Parts
(Checks
)) then
383 Set_Elsif_Parts
(Checks
, New_List
);
386 Append_To
(Elsif_Parts
(Checks
),
387 Make_Elsif_Part
(Loc
,
389 Then_Statements
=> New_List
(Error
)));
391 end Consequence_Error
;
397 function Declaration_Of
(Id
: Entity_Id
) return Node_Id
is
400 Make_Object_Declaration
(Loc
,
401 Defining_Identifier
=> Id
,
402 Object_Definition
=> New_Occurrence_Of
(Standard_Boolean
, Loc
),
403 Expression
=> New_Occurrence_Of
(Standard_False
, Loc
));
406 -------------------------------
407 -- Expand_Old_In_Consequence --
408 -------------------------------
410 procedure Expand_Old_In_Consequence
412 Evals
: in out Node_Id
;
416 Eval_Stmts
: List_Id
:= No_List
;
417 -- The evaluation sequence expressed as assignment statements of all
418 -- prefixes of attribute 'Old found in the current consequence.
420 function Expand_Old
(N
: Node_Id
) return Traverse_Result
;
421 -- Determine whether an arbitrary node denotes attribute 'Old and if
422 -- it does, perform all expansion-related actions.
428 function Expand_Old
(N
: Node_Id
) return Traverse_Result
is
434 if Nkind
(N
) = N_Attribute_Reference
435 and then Attribute_Name
(N
) = Name_Old
438 Temp
:= Make_Temporary
(Loc
, 'T', Pref
);
439 Set_Etype
(Temp
, Etype
(Pref
));
441 -- Generate a temporary to capture the value of the prefix:
442 -- Temp : <Pref type>;
445 Make_Object_Declaration
(Loc
,
446 Defining_Identifier
=> Temp
,
448 New_Occurrence_Of
(Etype
(Pref
), Loc
));
449 Set_No_Initialization
(Decl
);
451 Append_To
(Decls
, Decl
);
453 -- Evaluate the prefix, generate:
456 if No
(Eval_Stmts
) then
457 Eval_Stmts
:= New_List
;
460 Append_To
(Eval_Stmts
,
461 Make_Assignment_Statement
(Loc
,
462 Name
=> New_Occurrence_Of
(Temp
, Loc
),
463 Expression
=> Pref
));
465 -- Ensure that the prefix is valid
467 if Validity_Checks_On
and then Validity_Check_Operands
then
471 -- Replace the original attribute 'Old by a reference to the
472 -- generated temporary.
474 Rewrite
(N
, New_Occurrence_Of
(Temp
, Loc
));
480 procedure Expand_Olds
is new Traverse_Proc
(Expand_Old
);
482 -- Start of processing for Expand_Old_In_Consequence
485 -- Inspect the consequence and expand any attribute 'Old references
488 Expand_Olds
(Conseq
);
490 -- Augment the machinery to trigger the evaluation of all prefixes
491 -- found in the step above. If Eval is empty, then this is the first
492 -- consequence to yield expansion of 'Old. Generate:
495 -- <evaluation statements>
500 Make_Implicit_If_Statement
(CCs
,
501 Condition
=> New_Occurrence_Of
(Flag
, Loc
),
502 Then_Statements
=> Eval_Stmts
);
504 -- Otherwise generate:
506 -- <evaluation statements>
510 if No
(Elsif_Parts
(Evals
)) then
511 Set_Elsif_Parts
(Evals
, New_List
);
514 Append_To
(Elsif_Parts
(Evals
),
515 Make_Elsif_Part
(Loc
,
516 Condition
=> New_Occurrence_Of
(Flag
, Loc
),
517 Then_Statements
=> Eval_Stmts
));
519 end Expand_Old_In_Consequence
;
525 function Increment
(Id
: Entity_Id
) return Node_Id
is
528 Make_Assignment_Statement
(Loc
,
529 Name
=> New_Occurrence_Of
(Id
, Loc
),
532 Left_Opnd
=> New_Occurrence_Of
(Id
, Loc
),
533 Right_Opnd
=> Make_Integer_Literal
(Loc
, 1)));
540 function Set
(Id
: Entity_Id
) return Node_Id
is
543 Make_Assignment_Statement
(Loc
,
544 Name
=> New_Occurrence_Of
(Id
, Loc
),
545 Expression
=> New_Occurrence_Of
(Standard_True
, Loc
));
550 Aggr
: constant Node_Id
:=
552 (Pragma_Argument_Associations
(CCs
)));
553 Case_Guard
: Node_Id
;
557 Conseq_Checks
: Node_Id
:= Empty
;
559 Error_Decls
: List_Id
;
562 Multiple_PCs
: Boolean;
563 Old_Evals
: Node_Id
:= Empty
;
564 Others_Flag
: Entity_Id
:= Empty
;
567 -- Start of processing for Expand_Contract_Cases
570 -- Do nothing if pragma is not enabled. If pragma is disabled, it has
571 -- already been rewritten as a Null statement.
573 if Is_Ignored
(CCs
) then
576 -- Guard against malformed contract cases
578 elsif Nkind
(Aggr
) /= N_Aggregate
then
582 Multiple_PCs
:= List_Length
(Component_Associations
(Aggr
)) > 1;
584 -- Create the counter which tracks the number of case guards that
587 -- Count : Natural := 0;
589 Count
:= Make_Temporary
(Loc
, 'C');
592 Make_Object_Declaration
(Loc
,
593 Defining_Identifier
=> Count
,
594 Object_Definition
=> New_Occurrence_Of
(Standard_Natural
, Loc
),
595 Expression
=> Make_Integer_Literal
(Loc
, 0)));
597 -- Create the base error message for multiple overlapping case guards
599 -- Msg_Str : constant String :=
600 -- "contract cases overlap for subprogram Subp_Id";
603 Msg_Str
:= Make_Temporary
(Loc
, 'S');
606 Store_String_Chars
("contract cases overlap for subprogram ");
607 Store_String_Chars
(Get_Name_String
(Chars
(Subp_Id
)));
609 Error_Decls
:= New_List
(
610 Make_Object_Declaration
(Loc
,
611 Defining_Identifier
=> Msg_Str
,
612 Constant_Present
=> True,
613 Object_Definition
=> New_Occurrence_Of
(Standard_String
, Loc
),
614 Expression
=> Make_String_Literal
(Loc
, End_String
)));
617 -- Process individual post cases
619 Post_Case
:= First
(Component_Associations
(Aggr
));
620 while Present
(Post_Case
) loop
621 Case_Guard
:= First
(Choices
(Post_Case
));
622 Conseq
:= Expression
(Post_Case
);
624 -- The "others" choice requires special processing
626 if Nkind
(Case_Guard
) = N_Others_Choice
then
627 Others_Flag
:= Make_Temporary
(Loc
, 'F');
628 Prepend_To
(Decls
, Declaration_Of
(Others_Flag
));
630 -- Check possible overlap between a case guard and "others"
632 if Multiple_PCs
and Exception_Extra_Info
then
634 (Decls
=> Error_Decls
,
636 Error_Loc
=> Sloc
(Case_Guard
),
640 -- Inspect the consequence and perform special expansion of any
641 -- attribute 'Old references found within.
643 Expand_Old_In_Consequence
649 -- Check the corresponding consequence of "others"
652 (Checks
=> Conseq_Checks
,
659 -- Create the flag which tracks the state of its associated case
662 Flag
:= Make_Temporary
(Loc
, 'F');
663 Prepend_To
(Decls
, Declaration_Of
(Flag
));
665 -- The flag is set when the case guard is evaluated to True
666 -- if Case_Guard then
668 -- Count := Count + 1;
672 Make_Implicit_If_Statement
(CCs
,
673 Condition
=> Relocate_Node
(Case_Guard
),
674 Then_Statements
=> New_List
(
676 Increment
(Count
))));
678 -- Check whether this case guard overlaps with another one
680 if Multiple_PCs
and Exception_Extra_Info
then
682 (Decls
=> Error_Decls
,
684 Error_Loc
=> Sloc
(Case_Guard
),
688 -- Inspect the consequence and perform special expansion of any
689 -- attribute 'Old references found within.
691 Expand_Old_In_Consequence
697 -- The corresponding consequence of the case guard which evaluated
698 -- to True must hold on exit from the subprogram.
701 (Checks
=> Conseq_Checks
,
709 -- Raise Assertion_Error when none of the case guards evaluate to True.
710 -- The only exception is when we have "others", in which case there is
711 -- no error because "others" acts as a default True.
716 if Present
(Others_Flag
) then
717 CG_Stmts
:= New_List
(Set
(Others_Flag
));
720 -- raise Assertion_Error with "xxx contract cases incomplete";
724 Store_String_Chars
(Build_Location_String
(Loc
));
725 Store_String_Chars
(" contract cases incomplete");
727 CG_Stmts
:= New_List
(
728 Make_Procedure_Call_Statement
(Loc
,
730 New_Occurrence_Of
(RTE
(RE_Raise_Assert_Failure
), Loc
),
731 Parameter_Associations
=> New_List
(
732 Make_String_Literal
(Loc
, End_String
))));
736 Make_Implicit_If_Statement
(CCs
,
739 Left_Opnd
=> New_Occurrence_Of
(Count
, Loc
),
740 Right_Opnd
=> Make_Integer_Literal
(Loc
, 0)),
741 Then_Statements
=> CG_Stmts
);
743 -- Detect a possible failure due to several case guards evaluating to
747 -- elsif Count > 0 then
751 -- raise Assertion_Error with <Msg_Str>;
755 Set_Elsif_Parts
(CG_Checks
, New_List
(
756 Make_Elsif_Part
(Loc
,
759 Left_Opnd
=> New_Occurrence_Of
(Count
, Loc
),
760 Right_Opnd
=> Make_Integer_Literal
(Loc
, 1)),
762 Then_Statements
=> New_List
(
763 Make_Block_Statement
(Loc
,
764 Declarations
=> Error_Decls
,
765 Handled_Statement_Sequence
=>
766 Make_Handled_Sequence_Of_Statements
(Loc
,
767 Statements
=> New_List
(
768 Make_Procedure_Call_Statement
(Loc
,
771 (RTE
(RE_Raise_Assert_Failure
), Loc
),
772 Parameter_Associations
=> New_List
(
773 New_Occurrence_Of
(Msg_Str
, Loc
))))))))));
776 Append_To
(Decls
, CG_Checks
);
778 -- Once all case guards are evaluated and checked, evaluate any prefixes
779 -- of attribute 'Old founds in the selected consequence.
781 Append_To
(Decls
, Old_Evals
);
783 -- Raise Assertion_Error when the corresponding consequence of a case
784 -- guard that evaluated to True fails.
790 Append_To
(Stmts
, Conseq_Checks
);
791 end Expand_Contract_Cases
;
793 ---------------------
794 -- Expand_N_Pragma --
795 ---------------------
797 procedure Expand_N_Pragma
(N
: Node_Id
) is
798 Pname
: constant Name_Id
:= Pragma_Name
(N
);
801 -- Note: we may have a pragma whose Pragma_Identifier field is not a
802 -- recognized pragma, and we must ignore it at this stage.
804 if Is_Pragma_Name
(Pname
) then
805 case Get_Pragma_Id
(Pname
) is
807 -- Pragmas requiring special expander action
809 when Pragma_Abort_Defer
=>
810 Expand_Pragma_Abort_Defer
(N
);
813 Expand_Pragma_Check
(N
);
815 when Pragma_Common_Object
=>
816 Expand_Pragma_Common_Object
(N
);
818 when Pragma_Export_Exception
=>
819 Expand_Pragma_Import_Export_Exception
(N
);
821 when Pragma_Import
=>
822 Expand_Pragma_Import_Or_Interface
(N
);
824 when Pragma_Import_Exception
=>
825 Expand_Pragma_Import_Export_Exception
(N
);
827 when Pragma_Inspection_Point
=>
828 Expand_Pragma_Inspection_Point
(N
);
830 when Pragma_Interface
=>
831 Expand_Pragma_Import_Or_Interface
(N
);
833 when Pragma_Interrupt_Priority
=>
834 Expand_Pragma_Interrupt_Priority
(N
);
836 when Pragma_Loop_Variant
=>
837 Expand_Pragma_Loop_Variant
(N
);
839 when Pragma_Psect_Object
=>
840 Expand_Pragma_Psect_Object
(N
);
842 when Pragma_Relative_Deadline
=>
843 Expand_Pragma_Relative_Deadline
(N
);
845 -- All other pragmas need no expander action
853 -------------------------------
854 -- Expand_Pragma_Abort_Defer --
855 -------------------------------
857 -- An Abort_Defer pragma appears as the first statement in a handled
858 -- statement sequence (right after the begin). It defers aborts for
859 -- the entire statement sequence, but not for any declarations or
860 -- handlers (if any) associated with this statement sequence.
862 -- The transformation is to transform
864 -- pragma Abort_Defer;
873 -- when all others =>
874 -- Abort_Undefer.all;
877 -- Abort_Undefer_Direct;
880 procedure Expand_Pragma_Abort_Defer
(N
: Node_Id
) is
881 Loc
: constant Source_Ptr
:= Sloc
(N
);
885 Blk
: constant Entity_Id
:=
886 New_Internal_Entity
(E_Block
, Current_Scope
, Sloc
(N
), 'B');
889 Stms
:= New_List
(Build_Runtime_Call
(Loc
, RE_Abort_Defer
));
892 Stm
:= Remove_Next
(N
);
898 Make_Handled_Sequence_Of_Statements
(Loc
,
901 New_Occurrence_Of
(RTE
(RE_Abort_Undefer_Direct
), Loc
));
904 Make_Block_Statement
(Loc
,
905 Handled_Statement_Sequence
=> HSS
));
907 Set_Scope
(Blk
, Current_Scope
);
908 Set_Etype
(Blk
, Standard_Void_Type
);
909 Set_Identifier
(N
, New_Occurrence_Of
(Blk
, Sloc
(N
)));
910 Expand_At_End_Handler
(HSS
, Blk
);
912 end Expand_Pragma_Abort_Defer
;
914 --------------------------
915 -- Expand_Pragma_Check --
916 --------------------------
918 procedure Expand_Pragma_Check
(N
: Node_Id
) is
919 Loc
: constant Source_Ptr
:= Sloc
(N
);
920 -- Location of the pragma node. Note: it is important to use this
921 -- location (and not the location of the expression) for the generated
922 -- statements, otherwise the implicit return statement in the body
923 -- of a pre/postcondition subprogram may inherit the source location
924 -- of part of the expression, which causes confusing debug information
925 -- to be generated, which interferes with coverage analysis tools.
927 Cond
: constant Node_Id
:= Arg2
(N
);
928 Nam
: constant Name_Id
:= Chars
(Arg1
(N
));
932 -- Nothing to do if pragma is ignored
934 if Is_Ignored
(N
) then
938 -- Since this check is active, we rewrite the pragma into a
939 -- corresponding if statement, and then analyze the statement
941 -- The normal case expansion transforms:
943 -- pragma Check (name, condition [,message]);
947 -- if not condition then
948 -- System.Assertions.Raise_Assert_Failure (Str);
951 -- where Str is the message if one is present, or the default of
952 -- name failed at file:line if no message is given (the "name failed
953 -- at" is omitted for name = Assertion, since it is redundant, given
954 -- that the name of the exception is Assert_Failure.)
956 -- Also, instead of "XXX failed at", we generate slightly
957 -- different messages for some of the contract assertions (see
958 -- code below for details).
960 -- An alternative expansion is used when the No_Exception_Propagation
961 -- restriction is active and there is a local Assert_Failure handler.
962 -- This is not a common combination of circumstances, but it occurs in
963 -- the context of Aunit and the zero footprint profile. In this case we
966 -- if not condition then
967 -- raise Assert_Failure;
970 -- This will then be transformed into a goto, and the local handler will
971 -- be able to handle the assert error (which would not be the case if a
972 -- call is made to the Raise_Assert_Failure procedure).
974 -- We also generate the direct raise if the Suppress_Exception_Locations
975 -- is active, since we don't want to generate messages in this case.
977 -- Note that the reason we do not always generate a direct raise is that
978 -- the form in which the procedure is called allows for more efficient
979 -- breakpointing of assertion errors.
981 -- Generate the appropriate if statement. Note that we consider this to
982 -- be an explicit conditional in the source, not an implicit if, so we
983 -- do not call Make_Implicit_If_Statement.
985 -- Case where we generate a direct raise
987 if ((Debug_Flag_Dot_G
988 or else Restriction_Active
(No_Exception_Propagation
))
989 and then Present
(Find_Local_Handler
(RTE
(RE_Assert_Failure
), N
)))
990 or else (Opt
.Exception_Locations_Suppressed
and then No
(Arg3
(N
)))
993 Make_If_Statement
(Loc
,
997 Then_Statements
=> New_List
(
998 Make_Raise_Statement
(Loc
,
1000 New_Occurrence_Of
(RTE
(RE_Assert_Failure
), Loc
)))));
1002 -- Case where we call the procedure
1005 -- If we have a message given, use it
1007 if Present
(Arg3
(N
)) then
1008 Msg
:= Get_Pragma_Arg
(Arg3
(N
));
1010 -- Here we have no string, so prepare one
1014 Msg_Loc
: constant String :=
1015 Build_Location_String
(Sloc
(First_Node
(Cond
)));
1016 -- Source location used in the case of a failed assertion:
1017 -- point to the failing condition, not Loc. Note that the
1018 -- source location of the expression is not usually the best
1019 -- choice here. For example, it gets located on the last AND
1020 -- keyword in a chain of boolean expressiond AND'ed together.
1021 -- It is best to put the message on the first character of the
1022 -- condition, which is the effect of the First_Node call here.
1027 -- For Assert, we just use the location
1029 if Nam
= Name_Assert
then
1032 -- For predicate, we generate the string "predicate failed
1033 -- at yyy". We prefer all lower case for predicate.
1035 elsif Nam
= Name_Predicate
then
1036 Add_Str_To_Name_Buffer
("predicate failed at ");
1038 -- For special case of Precondition/Postcondition the string is
1039 -- "failed xx from yy" where xx is precondition/postcondition
1040 -- in all lower case. The reason for this different wording is
1041 -- that the failure is not at the point of occurrence of the
1042 -- pragma, unlike the other Check cases.
1044 elsif Nam_In
(Nam
, Name_Precondition
, Name_Postcondition
) then
1045 Get_Name_String
(Nam
);
1046 Insert_Str_In_Name_Buffer
("failed ", 1);
1047 Add_Str_To_Name_Buffer
(" from ");
1049 -- For special case of Invariant, the string is "failed
1050 -- invariant from yy", to be consistent with the string that is
1051 -- generated for the aspect case (the code later on checks for
1052 -- this specific string to modify it in some cases, so this is
1053 -- functionally important).
1055 elsif Nam
= Name_Invariant
then
1056 Add_Str_To_Name_Buffer
("failed invariant from ");
1058 -- For all other checks, the string is "xxx failed at yyy"
1059 -- where xxx is the check name with current source file casing.
1062 Get_Name_String
(Nam
);
1063 Set_Casing
(Identifier_Casing
(Current_Source_File
));
1064 Add_Str_To_Name_Buffer
(" failed at ");
1067 -- In all cases, add location string
1069 Add_Str_To_Name_Buffer
(Msg_Loc
);
1071 -- Build the message
1073 Msg
:= Make_String_Literal
(Loc
, Name_Buffer
(1 .. Name_Len
));
1077 -- Now rewrite as an if statement
1080 Make_If_Statement
(Loc
,
1083 Right_Opnd
=> Cond
),
1084 Then_Statements
=> New_List
(
1085 Make_Procedure_Call_Statement
(Loc
,
1087 New_Occurrence_Of
(RTE
(RE_Raise_Assert_Failure
), Loc
),
1088 Parameter_Associations
=> New_List
(Relocate_Node
(Msg
))))));
1093 -- If new condition is always false, give a warning
1095 if Warn_On_Assertion_Failure
1096 and then Nkind
(N
) = N_Procedure_Call_Statement
1097 and then Is_RTE
(Entity
(Name
(N
)), RE_Raise_Assert_Failure
)
1099 -- If original condition was a Standard.False, we assume that this is
1100 -- indeed intended to raise assert error and no warning is required.
1102 if Is_Entity_Name
(Original_Node
(Cond
))
1103 and then Entity
(Original_Node
(Cond
)) = Standard_False
1107 elsif Nam
= Name_Assert
then
1108 Error_Msg_N
("?A?assertion will fail at run time", N
);
1111 Error_Msg_N
("?A?check will fail at run time", N
);
1114 end Expand_Pragma_Check
;
1116 ---------------------------------
1117 -- Expand_Pragma_Common_Object --
1118 ---------------------------------
1120 -- Use a machine attribute to replicate semantic effect in DEC Ada
1122 -- pragma Machine_Attribute (intern_name, "common_object", extern_name);
1124 -- For now we do nothing with the size attribute ???
1126 -- Note: Psect_Object shares this processing
1128 procedure Expand_Pragma_Common_Object
(N
: Node_Id
) is
1129 Loc
: constant Source_Ptr
:= Sloc
(N
);
1131 Internal
: constant Node_Id
:= Arg1
(N
);
1132 External
: constant Node_Id
:= Arg2
(N
);
1135 -- Psect value upper cased as string literal
1137 Iloc
: constant Source_Ptr
:= Sloc
(Internal
);
1138 Eloc
: constant Source_Ptr
:= Sloc
(External
);
1142 -- Acquire Psect value and fold to upper case
1144 if Present
(External
) then
1145 if Nkind
(External
) = N_String_Literal
then
1146 String_To_Name_Buffer
(Strval
(External
));
1148 Get_Name_String
(Chars
(External
));
1154 Make_String_Literal
(Eloc
,
1155 Strval
=> String_From_Name_Buffer
);
1158 Get_Name_String
(Chars
(Internal
));
1161 Make_String_Literal
(Iloc
,
1162 Strval
=> String_From_Name_Buffer
);
1165 Ploc
:= Sloc
(Psect
);
1167 -- Insert the pragma
1169 Insert_After_And_Analyze
(N
,
1171 Chars
=> Name_Machine_Attribute
,
1172 Pragma_Argument_Associations
=> New_List
(
1173 Make_Pragma_Argument_Association
(Iloc
,
1174 Expression
=> New_Copy_Tree
(Internal
)),
1175 Make_Pragma_Argument_Association
(Eloc
,
1177 Make_String_Literal
(Sloc
=> Ploc
,
1178 Strval
=> "common_object")),
1179 Make_Pragma_Argument_Association
(Ploc
,
1180 Expression
=> New_Copy_Tree
(Psect
)))));
1182 end Expand_Pragma_Common_Object
;
1184 ---------------------------------------
1185 -- Expand_Pragma_Import_Or_Interface --
1186 ---------------------------------------
1188 procedure Expand_Pragma_Import_Or_Interface
(N
: Node_Id
) is
1190 Init_Call
: Node_Id
;
1193 -- In Relaxed_RM_Semantics, support old Ada 83 style:
1194 -- pragma Import (Entity, "external name");
1196 if Relaxed_RM_Semantics
1197 and then List_Length
(Pragma_Argument_Associations
(N
)) = 2
1198 and then Chars
(Pragma_Identifier
(N
)) = Name_Import
1199 and then Nkind
(Arg2
(N
)) = N_String_Literal
1201 Def_Id
:= Entity
(Arg1
(N
));
1203 Def_Id
:= Entity
(Arg2
(N
));
1208 if Ekind
(Def_Id
) = E_Variable
then
1210 -- When applied to a variable, the default initialization must not be
1211 -- done. As it is already done when the pragma is found, we just get
1212 -- rid of the call the initialization procedure which followed the
1213 -- object declaration. The call is inserted after the declaration,
1214 -- but validity checks may also have been inserted and thus the
1215 -- initialization call does not necessarily appear immediately
1216 -- after the object declaration.
1218 -- We can't use the freezing mechanism for this purpose, since we
1219 -- have to elaborate the initialization expression when it is first
1220 -- seen (so this elaboration cannot be deferred to the freeze point).
1222 -- Find and remove generated initialization call for object, if any
1224 Init_Call
:= Remove_Init_Call
(Def_Id
, Rep_Clause
=> N
);
1226 -- Any default initialization expression should be removed (e.g.
1227 -- null defaults for access objects, zero initialization of packed
1228 -- bit arrays). Imported objects aren't allowed to have explicit
1229 -- initialization, so the expression must have been generated by
1232 if No
(Init_Call
) and then Present
(Expression
(Parent
(Def_Id
))) then
1233 Set_Expression
(Parent
(Def_Id
), Empty
);
1236 -- Case of exception with convention C++
1238 elsif Ekind
(Def_Id
) = E_Exception
1239 and then Convention
(Def_Id
) = Convention_CPP
1241 -- Import a C++ convention
1244 Loc
: constant Source_Ptr
:= Sloc
(N
);
1245 Rtti_Name
: constant Node_Id
:= Arg3
(N
);
1246 Dum
: constant Entity_Id
:= Make_Temporary
(Loc
, 'D');
1248 Lang_Char
: Node_Id
;
1249 Foreign_Data
: Node_Id
;
1252 Exdata
:= Component_Associations
(Expression
(Parent
(Def_Id
)));
1254 Lang_Char
:= Next
(First
(Exdata
));
1256 -- Change the one-character language designator to 'C'
1258 Rewrite
(Expression
(Lang_Char
),
1259 Make_Character_Literal
(Loc
,
1261 Char_Literal_Value
=> UI_From_Int
(Character'Pos ('C'))));
1262 Analyze
(Expression
(Lang_Char
));
1264 -- Change the value of Foreign_Data
1266 Foreign_Data
:= Next
(Next
(Next
(Next
(Lang_Char
))));
1268 Insert_Actions
(Def_Id
, New_List
(
1269 Make_Object_Declaration
(Loc
,
1270 Defining_Identifier
=> Dum
,
1271 Object_Definition
=>
1272 New_Occurrence_Of
(Standard_Character
, Loc
)),
1275 Chars
=> Name_Import
,
1276 Pragma_Argument_Associations
=> New_List
(
1277 Make_Pragma_Argument_Association
(Loc
,
1278 Expression
=> Make_Identifier
(Loc
, Name_Ada
)),
1280 Make_Pragma_Argument_Association
(Loc
,
1281 Expression
=> Make_Identifier
(Loc
, Chars
(Dum
))),
1283 Make_Pragma_Argument_Association
(Loc
,
1284 Chars
=> Name_External_Name
,
1285 Expression
=> Relocate_Node
(Rtti_Name
))))));
1287 Rewrite
(Expression
(Foreign_Data
),
1288 Unchecked_Convert_To
(Standard_A_Char
,
1289 Make_Attribute_Reference
(Loc
,
1290 Prefix
=> Make_Identifier
(Loc
, Chars
(Dum
)),
1291 Attribute_Name
=> Name_Address
)));
1292 Analyze
(Expression
(Foreign_Data
));
1295 -- No special expansion required for any other case
1300 end Expand_Pragma_Import_Or_Interface
;
1302 -------------------------------------------
1303 -- Expand_Pragma_Import_Export_Exception --
1304 -------------------------------------------
1306 -- For a VMS exception fix up the language field with "VMS"
1307 -- instead of "Ada" (gigi needs this), create a constant that will be the
1308 -- value of the VMS condition code and stuff the Interface_Name field
1309 -- with the unexpanded name of the exception (if not already set).
1310 -- For a Ada exception, just stuff the Interface_Name field
1311 -- with the unexpanded name of the exception (if not already set).
1313 procedure Expand_Pragma_Import_Export_Exception
(N
: Node_Id
) is
1315 -- This pragma is only effective on OpenVMS systems, it was ignored
1316 -- on non-VMS systems, and we need to ignore it here as well.
1318 if not OpenVMS_On_Target
then
1323 Id
: constant Entity_Id
:= Entity
(Arg1
(N
));
1324 Call
: constant Node_Id
:= Register_Exception_Call
(Id
);
1325 Loc
: constant Source_Ptr
:= Sloc
(N
);
1328 if Present
(Call
) then
1330 Excep_Internal
: constant Node_Id
:= Make_Temporary
(Loc
, 'V');
1331 Export_Pragma
: Node_Id
;
1332 Excep_Alias
: Node_Id
;
1333 Excep_Object
: Node_Id
;
1334 Excep_Image
: String_Id
;
1336 Lang_Char
: Node_Id
;
1340 -- Compute the symbol for the code of the condition
1342 if Present
(Interface_Name
(Id
)) then
1343 Excep_Image
:= Strval
(Interface_Name
(Id
));
1345 Get_Name_String
(Chars
(Id
));
1347 Excep_Image
:= String_From_Name_Buffer
;
1350 Exdata
:= Component_Associations
(Expression
(Parent
(Id
)));
1352 if Is_VMS_Exception
(Id
) then
1353 Lang_Char
:= Next
(First
(Exdata
));
1355 -- Change the one-character language designator to 'V'
1357 Rewrite
(Expression
(Lang_Char
),
1358 Make_Character_Literal
(Loc
,
1360 Char_Literal_Value
=>
1361 UI_From_Int
(Character'Pos ('V'))));
1362 Analyze
(Expression
(Lang_Char
));
1364 if Exception_Code
(Id
) /= No_Uint
then
1366 -- The code for the exception is present. Create a linker
1367 -- alias to define the symbol.
1370 Unchecked_Convert_To
(RTE
(RE_Address
),
1371 Make_Integer_Literal
(Loc
,
1372 Intval
=> Exception_Code
(Id
)));
1374 -- Declare a dummy object
1377 Make_Object_Declaration
(Loc
,
1378 Defining_Identifier
=> Excep_Internal
,
1379 Object_Definition
=>
1380 New_Occurrence_Of
(RTE
(RE_Address
), Loc
));
1382 Insert_Action
(N
, Excep_Object
);
1383 Analyze
(Excep_Object
);
1385 -- Clear severity bits
1389 (UI_To_Int
(Exception_Code
(Id
)) / 8 * 8);
1391 -- Insert a pragma Linker_Alias to set the value of the
1392 -- dummy object symbol.
1396 Chars
=> Name_Linker_Alias
,
1397 Pragma_Argument_Associations
=> New_List
(
1398 Make_Pragma_Argument_Association
(Loc
,
1400 New_Occurrence_Of
(Excep_Internal
, Loc
)),
1402 Make_Pragma_Argument_Association
(Loc
,
1404 Make_String_Literal
(Loc
, End_String
))));
1406 Insert_Action
(N
, Excep_Alias
);
1407 Analyze
(Excep_Alias
);
1409 -- Insert a pragma Export to give a Linker_Name to the
1414 Chars
=> Name_Export
,
1415 Pragma_Argument_Associations
=> New_List
(
1416 Make_Pragma_Argument_Association
(Loc
,
1417 Expression
=> Make_Identifier
(Loc
, Name_C
)),
1419 Make_Pragma_Argument_Association
(Loc
,
1421 New_Occurrence_Of
(Excep_Internal
, Loc
)),
1423 Make_Pragma_Argument_Association
(Loc
,
1425 Make_String_Literal
(Loc
, Excep_Image
)),
1427 Make_Pragma_Argument_Association
(Loc
,
1429 Make_String_Literal
(Loc
, Excep_Image
))));
1431 Insert_Action
(N
, Export_Pragma
);
1432 Analyze
(Export_Pragma
);
1436 Make_Function_Call
(Loc
,
1438 New_Occurrence_Of
(RTE
(RE_Import_Address
), Loc
),
1439 Parameter_Associations
=> New_List
1440 (Make_String_Literal
(Loc
,
1441 Strval
=> Excep_Image
)));
1444 -- Generate the call to Register_VMS_Exception
1447 Make_Procedure_Call_Statement
(Loc
,
1448 Name
=> New_Occurrence_Of
1449 (RTE
(RE_Register_VMS_Exception
), Loc
),
1450 Parameter_Associations
=> New_List
(
1452 Unchecked_Convert_To
(RTE
(RE_Exception_Data_Ptr
),
1453 Make_Attribute_Reference
(Loc
,
1454 Prefix
=> New_Occurrence_Of
(Id
, Loc
),
1455 Attribute_Name
=> Name_Unrestricted_Access
)))));
1457 Analyze_And_Resolve
(Code
, RTE
(RE_Address
));
1461 if No
(Interface_Name
(Id
)) then
1462 Set_Interface_Name
(Id
,
1465 Strval
=> Excep_Image
));
1470 end Expand_Pragma_Import_Export_Exception
;
1472 ------------------------------------
1473 -- Expand_Pragma_Inspection_Point --
1474 ------------------------------------
1476 -- If no argument is given, then we supply a default argument list that
1477 -- includes all objects declared at the source level in all subprograms
1478 -- that enclose the inspection point pragma.
1480 procedure Expand_Pragma_Inspection_Point
(N
: Node_Id
) is
1481 Loc
: constant Source_Ptr
:= Sloc
(N
);
1488 if No
(Pragma_Argument_Associations
(N
)) then
1492 while S
/= Standard_Standard
loop
1493 E
:= First_Entity
(S
);
1494 while Present
(E
) loop
1495 if Comes_From_Source
(E
)
1496 and then Is_Object
(E
)
1497 and then not Is_Entry_Formal
(E
)
1498 and then Ekind
(E
) /= E_Component
1499 and then Ekind
(E
) /= E_Discriminant
1500 and then Ekind
(E
) /= E_Generic_In_Parameter
1501 and then Ekind
(E
) /= E_Generic_In_Out_Parameter
1504 Make_Pragma_Argument_Association
(Loc
,
1505 Expression
=> New_Occurrence_Of
(E
, Loc
)));
1514 Set_Pragma_Argument_Associations
(N
, A
);
1517 -- Expand the arguments of the pragma. Expanding an entity reference
1518 -- is a noop, except in a protected operation, where a reference may
1519 -- have to be transformed into a reference to the corresponding prival.
1520 -- Are there other pragmas that may require this ???
1522 Assoc
:= First
(Pragma_Argument_Associations
(N
));
1524 while Present
(Assoc
) loop
1525 Expand
(Expression
(Assoc
));
1528 end Expand_Pragma_Inspection_Point
;
1530 --------------------------------------
1531 -- Expand_Pragma_Interrupt_Priority --
1532 --------------------------------------
1534 -- Supply default argument if none exists (System.Interrupt_Priority'Last)
1536 procedure Expand_Pragma_Interrupt_Priority
(N
: Node_Id
) is
1537 Loc
: constant Source_Ptr
:= Sloc
(N
);
1540 if No
(Pragma_Argument_Associations
(N
)) then
1541 Set_Pragma_Argument_Associations
(N
, New_List
(
1542 Make_Pragma_Argument_Association
(Loc
,
1544 Make_Attribute_Reference
(Loc
,
1546 New_Occurrence_Of
(RTE
(RE_Interrupt_Priority
), Loc
),
1547 Attribute_Name
=> Name_Last
))));
1549 end Expand_Pragma_Interrupt_Priority
;
1551 --------------------------------
1552 -- Expand_Pragma_Loop_Variant --
1553 --------------------------------
1555 -- Pragma Loop_Variant is expanded in the following manner:
1559 -- for | while ... loop
1560 -- <preceding source statements>
1561 -- pragma Loop_Variant
1562 -- (Increases => Incr_Expr,
1563 -- Decreases => Decr_Expr);
1564 -- <succeeding source statements>
1569 -- Curr_1 : <type of Incr_Expr>;
1570 -- Curr_2 : <type of Decr_Expr>;
1571 -- Old_1 : <type of Incr_Expr>;
1572 -- Old_2 : <type of Decr_Expr>;
1573 -- Flag : Boolean := False;
1575 -- for | while ... loop
1576 -- <preceding source statements>
1583 -- Curr_1 := <Incr_Expr>;
1584 -- Curr_2 := <Decr_Expr>;
1587 -- if Curr_1 /= Old_1 then
1588 -- pragma Check (Loop_Variant, Curr_1 > Old_1);
1590 -- pragma Check (Loop_Variant, Curr_2 < Old_2);
1596 -- <succeeding source statements>
1599 procedure Expand_Pragma_Loop_Variant
(N
: Node_Id
) is
1600 Loc
: constant Source_Ptr
:= Sloc
(N
);
1602 Last_Var
: constant Node_Id
:= Last
(Pragma_Argument_Associations
(N
));
1604 Curr_Assign
: List_Id
:= No_List
;
1605 Flag_Id
: Entity_Id
:= Empty
;
1606 If_Stmt
: Node_Id
:= Empty
;
1607 Old_Assign
: List_Id
:= No_List
;
1608 Loop_Scop
: Entity_Id
;
1609 Loop_Stmt
: Node_Id
;
1612 procedure Process_Variant
(Variant
: Node_Id
; Is_Last
: Boolean);
1613 -- Process a single increasing / decreasing termination variant. Flag
1614 -- Is_Last should be set when processing the last variant.
1616 ---------------------
1617 -- Process_Variant --
1618 ---------------------
1620 procedure Process_Variant
(Variant
: Node_Id
; Is_Last
: Boolean) is
1624 Old_Val
: Node_Id
) return Node_Id
;
1625 -- Generate a comparison between Curr_Val and Old_Val depending on
1626 -- the change mode (Increases / Decreases) of the variant.
1635 Old_Val
: Node_Id
) return Node_Id
1638 if Chars
(Variant
) = Name_Increases
then
1639 return Make_Op_Gt
(Loc
, Curr_Val
, Old_Val
);
1640 else pragma Assert
(Chars
(Variant
) = Name_Decreases
);
1641 return Make_Op_Lt
(Loc
, Curr_Val
, Old_Val
);
1647 Expr
: constant Node_Id
:= Expression
(Variant
);
1648 Expr_Typ
: constant Entity_Id
:= Etype
(Expr
);
1649 Loc
: constant Source_Ptr
:= Sloc
(Expr
);
1650 Loop_Loc
: constant Source_Ptr
:= Sloc
(Loop_Stmt
);
1651 Curr_Id
: Entity_Id
;
1655 -- Start of processing for Process_Variant
1658 -- All temporaries generated in this routine must be inserted before
1659 -- the related loop statement. Ensure that the proper scope is on the
1660 -- stack when analyzing the temporaries. Note that we also use the
1661 -- Sloc of the related loop.
1663 Push_Scope
(Scope
(Loop_Scop
));
1665 -- Step 1: Create the declaration of the flag which controls the
1666 -- behavior of the assertion on the first iteration of the loop.
1668 if No
(Flag_Id
) then
1671 -- Flag : Boolean := False;
1673 Flag_Id
:= Make_Temporary
(Loop_Loc
, 'F');
1675 Insert_Action
(Loop_Stmt
,
1676 Make_Object_Declaration
(Loop_Loc
,
1677 Defining_Identifier
=> Flag_Id
,
1678 Object_Definition
=>
1679 New_Occurrence_Of
(Standard_Boolean
, Loop_Loc
),
1681 New_Occurrence_Of
(Standard_False
, Loop_Loc
)));
1683 -- Prevent an unwanted optimization where the Current_Value of
1684 -- the flag eliminates the if statement which stores the variant
1685 -- values coming from the previous iteration.
1687 -- Flag : Boolean := False;
1689 -- if Flag then -- condition rewritten to False
1690 -- Old_N := Curr_N; -- and if statement eliminated
1696 Set_Current_Value
(Flag_Id
, Empty
);
1699 -- Step 2: Create the temporaries which store the old and current
1700 -- values of the associated expression.
1703 -- Curr : <type of Expr>;
1705 Curr_Id
:= Make_Temporary
(Loc
, 'C');
1707 Insert_Action
(Loop_Stmt
,
1708 Make_Object_Declaration
(Loop_Loc
,
1709 Defining_Identifier
=> Curr_Id
,
1710 Object_Definition
=> New_Occurrence_Of
(Expr_Typ
, Loop_Loc
)));
1713 -- Old : <type of Expr>;
1715 Old_Id
:= Make_Temporary
(Loc
, 'P');
1717 Insert_Action
(Loop_Stmt
,
1718 Make_Object_Declaration
(Loop_Loc
,
1719 Defining_Identifier
=> Old_Id
,
1720 Object_Definition
=> New_Occurrence_Of
(Expr_Typ
, Loop_Loc
)));
1722 -- Restore original scope after all temporaries have been analyzed
1726 -- Step 3: Store value of the expression from the previous iteration
1728 if No
(Old_Assign
) then
1729 Old_Assign
:= New_List
;
1735 Append_To
(Old_Assign
,
1736 Make_Assignment_Statement
(Loc
,
1737 Name
=> New_Occurrence_Of
(Old_Id
, Loc
),
1738 Expression
=> New_Occurrence_Of
(Curr_Id
, Loc
)));
1740 -- Step 4: Store the current value of the expression
1742 if No
(Curr_Assign
) then
1743 Curr_Assign
:= New_List
;
1749 Append_To
(Curr_Assign
,
1750 Make_Assignment_Statement
(Loc
,
1751 Name
=> New_Occurrence_Of
(Curr_Id
, Loc
),
1752 Expression
=> Relocate_Node
(Expr
)));
1754 -- Step 5: Create corresponding assertion to verify change of value
1757 -- pragma Check (Loop_Variant, Curr <|> Old);
1761 Chars
=> Name_Check
,
1762 Pragma_Argument_Associations
=> New_List
(
1763 Make_Pragma_Argument_Association
(Loc
,
1764 Expression
=> Make_Identifier
(Loc
, Name_Loop_Variant
)),
1765 Make_Pragma_Argument_Association
(Loc
,
1768 Curr_Val
=> New_Occurrence_Of
(Curr_Id
, Loc
),
1769 Old_Val
=> New_Occurrence_Of
(Old_Id
, Loc
)))));
1772 -- if Curr /= Old then
1775 if No
(If_Stmt
) then
1777 -- When there is just one termination variant, do not compare the
1778 -- old and current value for equality, just check the pragma.
1784 Make_If_Statement
(Loc
,
1787 Left_Opnd
=> New_Occurrence_Of
(Curr_Id
, Loc
),
1788 Right_Opnd
=> New_Occurrence_Of
(Old_Id
, Loc
)),
1789 Then_Statements
=> New_List
(Prag
));
1798 Set_Else_Statements
(If_Stmt
, New_List
(Prag
));
1801 -- elsif Curr /= Old then
1805 if Elsif_Parts
(If_Stmt
) = No_List
then
1806 Set_Elsif_Parts
(If_Stmt
, New_List
);
1809 Append_To
(Elsif_Parts
(If_Stmt
),
1810 Make_Elsif_Part
(Loc
,
1813 Left_Opnd
=> New_Occurrence_Of
(Curr_Id
, Loc
),
1814 Right_Opnd
=> New_Occurrence_Of
(Old_Id
, Loc
)),
1815 Then_Statements
=> New_List
(Prag
)));
1817 end Process_Variant
;
1819 -- Start of processing for Expand_Pragma_Loop_Variant
1822 -- If pragma is not enabled, rewrite as Null statement. If pragma is
1823 -- disabled, it has already been rewritten as a Null statement.
1825 if Is_Ignored
(N
) then
1826 Rewrite
(N
, Make_Null_Statement
(Loc
));
1831 -- Locate the enclosing loop for which this assertion applies. In the
1832 -- case of Ada 2012 array iteration, we might be dealing with nested
1833 -- loops. Only the outermost loop has an identifier.
1836 while Present
(Loop_Stmt
) loop
1837 if Nkind
(Loop_Stmt
) = N_Loop_Statement
1838 and then Present
(Identifier
(Loop_Stmt
))
1843 Loop_Stmt
:= Parent
(Loop_Stmt
);
1846 Loop_Scop
:= Entity
(Identifier
(Loop_Stmt
));
1848 -- Create the circuitry which verifies individual variants
1850 Variant
:= First
(Pragma_Argument_Associations
(N
));
1851 while Present
(Variant
) loop
1852 Process_Variant
(Variant
, Is_Last
=> Variant
= Last_Var
);
1857 -- Construct the segment which stores the old values of all expressions.
1864 Make_If_Statement
(Loc
,
1865 Condition
=> New_Occurrence_Of
(Flag_Id
, Loc
),
1866 Then_Statements
=> Old_Assign
));
1868 -- Update the values of all expressions
1870 Insert_Actions
(N
, Curr_Assign
);
1872 -- Add the assertion circuitry to test all changes in expressions.
1881 Make_If_Statement
(Loc
,
1882 Condition
=> New_Occurrence_Of
(Flag_Id
, Loc
),
1883 Then_Statements
=> New_List
(If_Stmt
),
1884 Else_Statements
=> New_List
(
1885 Make_Assignment_Statement
(Loc
,
1886 Name
=> New_Occurrence_Of
(Flag_Id
, Loc
),
1887 Expression
=> New_Occurrence_Of
(Standard_True
, Loc
)))));
1889 -- Note: the pragma has been completely transformed into a sequence of
1890 -- corresponding declarations and statements. We leave it in the tree
1891 -- for documentation purposes. It will be ignored by the backend.
1893 end Expand_Pragma_Loop_Variant
;
1895 --------------------------------
1896 -- Expand_Pragma_Psect_Object --
1897 --------------------------------
1899 -- Convert to Common_Object, and expand the resulting pragma
1901 procedure Expand_Pragma_Psect_Object
(N
: Node_Id
)
1902 renames Expand_Pragma_Common_Object
;
1904 -------------------------------------
1905 -- Expand_Pragma_Relative_Deadline --
1906 -------------------------------------
1908 procedure Expand_Pragma_Relative_Deadline
(N
: Node_Id
) is
1909 P
: constant Node_Id
:= Parent
(N
);
1910 Loc
: constant Source_Ptr
:= Sloc
(N
);
1913 -- Expand the pragma only in the case of the main subprogram. For tasks
1914 -- the expansion is done in exp_ch9. Generate a call to Set_Deadline
1915 -- at Clock plus the relative deadline specified in the pragma. Time
1916 -- values are translated into Duration to allow for non-private
1917 -- addition operation.
1919 if Nkind
(P
) = N_Subprogram_Body
then
1922 Make_Procedure_Call_Statement
(Loc
,
1923 Name
=> New_Occurrence_Of
(RTE
(RE_Set_Deadline
), Loc
),
1924 Parameter_Associations
=> New_List
(
1925 Unchecked_Convert_To
(RTE
(RO_RT_Time
),
1928 Make_Function_Call
(Loc
,
1929 New_Occurrence_Of
(RTE
(RO_RT_To_Duration
), Loc
),
1930 New_List
(Make_Function_Call
(Loc
,
1931 New_Occurrence_Of
(RTE
(RE_Clock
), Loc
)))),
1933 Unchecked_Convert_To
(Standard_Duration
, Arg1
(N
)))))));
1937 end Expand_Pragma_Relative_Deadline
;