1 ------------------------------------------------------------------------------
3 -- GNAT COMPILER COMPONENTS --
9 -- Copyright (C) 2009-2012, 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 Debug; use Debug;
28 with Errout; use Errout;
30 with Lib.Util; use Lib.Util;
31 with Namet; use Namet;
32 with Nlists; use Nlists;
34 with Output; use Output;
37 with Sinfo; use Sinfo;
38 with Sinput; use Sinput;
39 with Snames; use Snames;
42 with GNAT.HTable; use GNAT.HTable;
43 with GNAT.Heap_Sort_G;
45 package body Par_SCO is
47 -----------------------
48 -- Unit Number Table --
49 -----------------------
51 -- This table parallels the SCO_Unit_Table, keeping track of the unit
52 -- numbers corresponding to the entries made in this table, so that before
53 -- writing out the SCO information to the ALI file, we can fill in the
54 -- proper dependency numbers and file names.
56 -- Note that the zero'th entry is here for convenience in sorting the
57 -- table, the real lower bound is 1.
59 package SCO_Unit_Number_Table is new Table.Table (
60 Table_Component_Type => Unit_Number_Type,
61 Table_Index_Type => SCO_Unit_Index,
62 Table_Low_Bound => 0, -- see note above on sort
64 Table_Increment => 200,
65 Table_Name => "SCO_Unit_Number_Entry");
67 ---------------------------------
68 -- Condition/Pragma Hash Table --
69 ---------------------------------
71 -- We need to be able to get to conditions quickly for handling the calls
72 -- to Set_SCO_Condition efficiently, and similarly to get to pragmas to
73 -- handle calls to Set_SCO_Pragma_Enabled. For this purpose we identify the
74 -- conditions and pragmas in the table by their starting sloc, and use this
75 -- hash table to map from these sloc values to SCO_Table indexes.
77 type Header_Num is new Integer range 0 .. 996;
78 -- Type for hash table headers
80 function Hash (F : Source_Ptr) return Header_Num;
81 -- Function to Hash source pointer value
83 function Equal (F1, F2 : Source_Ptr) return Boolean;
84 -- Function to test two keys for equality
86 package Condition_Pragma_Hash_Table is new Simple_HTable
87 (Header_Num, Int, 0, Source_Ptr, Hash, Equal);
88 -- The actual hash table
90 --------------------------
91 -- Internal Subprograms --
92 --------------------------
94 function Has_Decision (N : Node_Id) return Boolean;
95 -- N is the node for a subexpression. Returns True if the subexpression
96 -- contains a nested decision (i.e. either is a logical operator, or
97 -- contains a logical operator in its subtree).
99 function Is_Logical_Operator (N : Node_Id) return Boolean;
100 -- N is the node for a subexpression. This procedure just tests N to see
101 -- if it is a logical operator (including short circuit conditions, but
102 -- excluding OR and AND) and returns True if so, False otherwise, it does
103 -- no other processing.
105 procedure Process_Decisions
108 Pragma_Sloc : Source_Ptr);
109 -- If N is Empty, has no effect. Otherwise scans the tree for the node N,
110 -- to output any decisions it contains. T is one of IEGPWX (for context of
111 -- expression: if/exit when/entry guard/pragma/while/expression). If T is
112 -- other than X, the node N is the conditional expression involved, and a
113 -- decision is always present (at the very least a simple decision is
114 -- present at the top level).
116 procedure Process_Decisions
119 Pragma_Sloc : Source_Ptr);
120 -- Calls above procedure for each element of the list L
122 procedure Set_Table_Entry
128 Pragma_Sloc : Source_Ptr := No_Location;
129 Pragma_Name : Pragma_Id := Unknown_Pragma);
130 -- Append an entry to SCO_Table with fields set as per arguments
132 type Dominant_Info is record
134 -- F/T/S/E for a valid dominance marker, or ' ' for no dominant
137 -- Node providing the Sloc(s) for the dominance marker
139 No_Dominant : constant Dominant_Info := (' ', Empty);
141 procedure Traverse_Declarations_Or_Statements
143 D : Dominant_Info := No_Dominant;
144 P : Node_Id := Empty);
145 -- Process L, a list of statements or declarations dominated by D.
146 -- If P is present, it is processed as though it had been prepended to L.
148 procedure Traverse_Generic_Instantiation (N : Node_Id);
149 procedure Traverse_Generic_Package_Declaration (N : Node_Id);
150 procedure Traverse_Handled_Statement_Sequence
152 D : Dominant_Info := No_Dominant);
153 procedure Traverse_Package_Body (N : Node_Id);
154 procedure Traverse_Package_Declaration (N : Node_Id);
155 procedure Traverse_Protected_Body (N : Node_Id);
156 procedure Traverse_Subprogram_Or_Task_Body
158 D : Dominant_Info := No_Dominant);
159 procedure Traverse_Subprogram_Declaration (N : Node_Id);
160 -- Traverse the corresponding construct, generating SCO table entries
162 procedure Write_SCOs_To_ALI_File is new Put_SCOs;
163 -- Write SCO information to the ALI file using routines in Lib.Util
171 -- Dump SCO unit table
173 Write_Line ("SCO Unit Table");
174 Write_Line ("--------------");
176 for Index in 1 .. SCO_Unit_Table.Last loop
178 UTE : SCO_Unit_Table_Entry renames SCO_Unit_Table.Table (Index);
182 Write_Int (Int (Index));
183 Write_Str (". Dep_Num = ");
184 Write_Int (Int (UTE.Dep_Num));
185 Write_Str (" From = ");
186 Write_Int (Int (UTE.From));
187 Write_Str (" To = ");
188 Write_Int (Int (UTE.To));
190 Write_Str (" File_Name = """);
192 if UTE.File_Name /= null then
193 Write_Str (UTE.File_Name.all);
201 -- Dump SCO Unit number table if it contains any entries
203 if SCO_Unit_Number_Table.Last >= 1 then
205 Write_Line ("SCO Unit Number Table");
206 Write_Line ("---------------------");
208 for Index in 1 .. SCO_Unit_Number_Table.Last loop
210 Write_Int (Int (Index));
211 Write_Str (". Unit_Number = ");
212 Write_Int (Int (SCO_Unit_Number_Table.Table (Index)));
217 -- Dump SCO table itself
220 Write_Line ("SCO Table");
221 Write_Line ("---------");
223 for Index in 1 .. SCO_Table.Last loop
225 T : SCO_Table_Entry renames SCO_Table.Table (Index);
233 Write_Str (" C1 = '");
239 Write_Str (" C2 = '");
244 if T.From /= No_Source_Location then
245 Write_Str (" From = ");
246 Write_Int (Int (T.From.Line));
248 Write_Int (Int (T.From.Col));
251 if T.To /= No_Source_Location then
252 Write_Str (" To = ");
253 Write_Int (Int (T.To.Line));
255 Write_Int (Int (T.To.Col));
261 Write_Str (" False");
273 function Equal (F1, F2 : Source_Ptr) return Boolean is
282 function Has_Decision (N : Node_Id) return Boolean is
284 function Check_Node (N : Node_Id) return Traverse_Result;
290 function Check_Node (N : Node_Id) return Traverse_Result is
292 if Is_Logical_Operator (N) then
299 function Traverse is new Traverse_Func (Check_Node);
301 -- Start of processing for Has_Decision
304 return Traverse (N) = Abandon;
311 function Hash (F : Source_Ptr) return Header_Num is
313 return Header_Num (Nat (F) mod 997);
320 procedure Initialize is
322 SCO_Unit_Number_Table.Init;
324 -- Set dummy 0'th entry in place for sort
326 SCO_Unit_Number_Table.Increment_Last;
329 -------------------------
330 -- Is_Logical_Operator --
331 -------------------------
333 function Is_Logical_Operator (N : Node_Id) return Boolean is
335 return Nkind_In (N, N_Op_Not, N_And_Then, N_Or_Else);
336 end Is_Logical_Operator;
338 -----------------------
339 -- Process_Decisions --
340 -----------------------
342 -- Version taking a list
344 procedure Process_Decisions
347 Pragma_Sloc : Source_Ptr)
353 while Present (N) loop
354 Process_Decisions (N, T, Pragma_Sloc);
358 end Process_Decisions;
360 -- Version taking a node
362 Current_Pragma_Sloc : Source_Ptr := No_Location;
363 -- While processing a pragma, this is set to the sloc of the N_Pragma node
365 procedure Process_Decisions
368 Pragma_Sloc : Source_Ptr)
371 -- This is used to mark the location of a decision sequence in the SCO
372 -- table. We use it for backing out a simple decision in an expression
373 -- context that contains only NOT operators.
375 X_Not_Decision : Boolean;
376 -- This flag keeps track of whether a decision sequence in the SCO table
377 -- contains only NOT operators, and is for an expression context (T=X).
378 -- The flag will be set False if T is other than X, or if an operator
379 -- other than NOT is in the sequence.
381 function Process_Node (N : Node_Id) return Traverse_Result;
382 -- Processes one node in the traversal, looking for logical operators,
383 -- and if one is found, outputs the appropriate table entries.
385 procedure Output_Decision_Operand (N : Node_Id);
386 -- The node N is the top level logical operator of a decision, or it is
387 -- one of the operands of a logical operator belonging to a single
388 -- complex decision. This routine outputs the sequence of table entries
389 -- corresponding to the node. Note that we do not process the sub-
390 -- operands to look for further decisions, that processing is done in
391 -- Process_Decision_Operand, because we can't get decisions mixed up in
392 -- the global table. Call has no effect if N is Empty.
394 procedure Output_Element (N : Node_Id);
395 -- Node N is an operand of a logical operator that is not itself a
396 -- logical operator, or it is a simple decision. This routine outputs
397 -- the table entry for the element, with C1 set to ' '. Last is set
398 -- False, and an entry is made in the condition hash table.
400 procedure Output_Header (T : Character);
401 -- Outputs a decision header node. T is I/W/E/P for IF/WHILE/EXIT WHEN/
402 -- PRAGMA, and 'X' for the expression case.
404 procedure Process_Decision_Operand (N : Node_Id);
405 -- This is called on node N, the top level node of a decision, or on one
406 -- of its operands or suboperands after generating the full output for
407 -- the complex decision. It process the suboperands of the decision
408 -- looking for nested decisions.
410 -----------------------------
411 -- Output_Decision_Operand --
412 -----------------------------
414 procedure Output_Decision_Operand (N : Node_Id) is
424 elsif Is_Logical_Operator (N) then
425 if Nkind (N) = N_Op_Not then
432 if Nkind_In (N, N_Op_Or, N_Or_Else) then
446 Output_Decision_Operand (L);
447 Output_Decision_Operand (Right_Opnd (N));
449 -- Not a logical operator
454 end Output_Decision_Operand;
460 procedure Output_Element (N : Node_Id) is
464 Sloc_Range (N, FSloc, LSloc);
471 Condition_Pragma_Hash_Table.Set (FSloc, SCO_Table.Last);
478 procedure Output_Header (T : Character) is
479 Loc : Source_Ptr := No_Location;
480 -- Node whose Sloc is used for the decision
484 when 'I' | 'E' | 'W' =>
486 -- For IF, EXIT, WHILE, the token SLOC can be found from
487 -- the SLOC of the parent of the expression.
489 Loc := Sloc (Parent (N));
493 -- For entry guard, the token sloc is from the N_Entry_Body.
494 -- For PRAGMA, we must get the location from the pragma node.
495 -- Argument N is the pragma argument, and we have to go up two
496 -- levels (through the pragma argument association) to get to
497 -- the pragma node itself. For the guard on a select
498 -- alternative, we do not have access to the token location
499 -- for the WHEN, so we use the first sloc of the condition
500 -- itself (note: we use First_Sloc, not Sloc, because this is
501 -- what is referenced by dominance markers).
503 if Nkind_In (Parent (N), N_Accept_Alternative,
505 N_Terminate_Alternative)
507 Loc := First_Sloc (N);
509 Loc := Sloc (Parent (Parent (N)));
514 -- For an expression, no Sloc
518 -- No other possibilities
530 Pragma_Sloc => Pragma_Sloc);
533 ------------------------------
534 -- Process_Decision_Operand --
535 ------------------------------
537 procedure Process_Decision_Operand (N : Node_Id) is
539 if Is_Logical_Operator (N) then
540 if Nkind (N) /= N_Op_Not then
541 Process_Decision_Operand (Left_Opnd (N));
542 X_Not_Decision := False;
545 Process_Decision_Operand (Right_Opnd (N));
548 Process_Decisions (N, 'X', Pragma_Sloc);
550 end Process_Decision_Operand;
556 function Process_Node (N : Node_Id) return Traverse_Result is
560 -- Logical operators, output table entries and then process
561 -- operands recursively to deal with nested conditions.
563 when N_And_Then | N_Or_Else | N_Op_Not =>
568 -- If outer level, then type comes from call, otherwise it
569 -- is more deeply nested and counts as X for expression.
571 if N = Process_Decisions.N then
572 T := Process_Decisions.T;
577 -- Output header for sequence
579 X_Not_Decision := T = 'X' and then Nkind (N) = N_Op_Not;
580 Mark := SCO_Table.Last;
583 -- Output the decision
585 Output_Decision_Operand (N);
587 -- If the decision was in an expression context (T = 'X')
588 -- and contained only NOT operators, then we don't output
591 if X_Not_Decision then
592 SCO_Table.Set_Last (Mark);
594 -- Otherwise, set Last in last table entry to mark end
597 SCO_Table.Table (SCO_Table.Last).Last := True;
600 -- Process any embedded decisions
602 Process_Decision_Operand (N);
608 when N_Case_Expression =>
611 -- Conditional expression, processed like an if statement
613 when N_Conditional_Expression =>
615 Cond : constant Node_Id := First (Expressions (N));
616 Thnx : constant Node_Id := Next (Cond);
617 Elsx : constant Node_Id := Next (Thnx);
619 Process_Decisions (Cond, 'I', Pragma_Sloc);
620 Process_Decisions (Thnx, 'X', Pragma_Sloc);
621 Process_Decisions (Elsx, 'X', Pragma_Sloc);
625 -- All other cases, continue scan
633 procedure Traverse is new Traverse_Proc (Process_Node);
635 -- Start of processing for Process_Decisions
642 -- See if we have simple decision at outer level and if so then
643 -- generate the decision entry for this simple decision. A simple
644 -- decision is a boolean expression (which is not a logical operator
645 -- or short circuit form) appearing as the operand of an IF, WHILE,
646 -- EXIT WHEN, or special PRAGMA construct.
648 if T /= 'X' and then not Is_Logical_Operator (N) then
652 -- Change Last in last table entry to True to mark end of
653 -- sequence, which is this case is only one element long.
655 SCO_Table.Table (SCO_Table.Last).Last := True;
659 end Process_Decisions;
667 procedure Write_Info_Char (C : Character) renames Write_Char;
668 -- Write one character;
670 procedure Write_Info_Initiate (Key : Character) renames Write_Char;
671 -- Start new one and write one character;
673 procedure Write_Info_Nat (N : Nat);
676 procedure Write_Info_Terminate renames Write_Eol;
677 -- Terminate current line
683 procedure Write_Info_Nat (N : Nat) is
688 procedure Debug_Put_SCOs is new Put_SCOs;
690 -- Start of processing for pscos
700 procedure SCO_Output is
702 if Debug_Flag_Dot_OO then
706 -- Sort the unit tables based on dependency numbers
708 Unit_Table_Sort : declare
710 function Lt (Op1, Op2 : Natural) return Boolean;
711 -- Comparison routine for sort call
713 procedure Move (From : Natural; To : Natural);
714 -- Move routine for sort call
720 function Lt (Op1, Op2 : Natural) return Boolean is
724 (SCO_Unit_Number_Table.Table (SCO_Unit_Index (Op1)))
727 (SCO_Unit_Number_Table.Table (SCO_Unit_Index (Op2)));
734 procedure Move (From : Natural; To : Natural) is
736 SCO_Unit_Table.Table (SCO_Unit_Index (To)) :=
737 SCO_Unit_Table.Table (SCO_Unit_Index (From));
738 SCO_Unit_Number_Table.Table (SCO_Unit_Index (To)) :=
739 SCO_Unit_Number_Table.Table (SCO_Unit_Index (From));
742 package Sorting is new GNAT.Heap_Sort_G (Move, Lt);
744 -- Start of processing for Unit_Table_Sort
747 Sorting.Sort (Integer (SCO_Unit_Table.Last));
750 -- Loop through entries in the unit table to set file name and
751 -- dependency number entries.
753 for J in 1 .. SCO_Unit_Table.Last loop
755 U : constant Unit_Number_Type := SCO_Unit_Number_Table.Table (J);
756 UTE : SCO_Unit_Table_Entry renames SCO_Unit_Table.Table (J);
758 Get_Name_String (Reference_Name (Source_Index (U)));
759 UTE.File_Name := new String'(Name_Buffer (1 .. Name_Len));
760 UTE.Dep_Num := Dependency_Num (U);
764 -- Now the tables are all setup for output to the ALI file
766 Write_SCOs_To_ALI_File;
769 -------------------------
770 -- SCO_Pragma_Disabled --
771 -------------------------
773 function SCO_Pragma_Disabled (Loc : Source_Ptr) return Boolean is
777 if Loc = No_Location then
781 Index := Condition_Pragma_Hash_Table.Get (Loc);
783 -- The test here for zero is to deal with possible previous errors, and
784 -- for the case of pragma statement SCOs, for which we always set the
785 -- Pragma_Sloc even if the particular pragma cannot be specifically
790 T : SCO_Table_Entry renames SCO_Table.Table (Index);
792 pragma Assert (T.C1 = 'S');
799 end SCO_Pragma_Disabled;
805 procedure SCO_Record (U : Unit_Number_Type) is
810 -- Ignore call if not generating code and generating SCO's
812 if not (Generate_SCO and then Operating_Mode = Generate_Code) then
816 -- Ignore call if this unit already recorded
818 for J in 1 .. SCO_Unit_Number_Table.Last loop
819 if U = SCO_Unit_Number_Table.Table (J) then
824 -- Otherwise record starting entry
826 From := SCO_Table.Last + 1;
828 -- Get Unit (checking case of subunit)
830 Lu := Unit (Cunit (U));
832 if Nkind (Lu) = N_Subunit then
833 Lu := Proper_Body (Lu);
839 when N_Protected_Body =>
840 Traverse_Protected_Body (Lu);
842 when N_Subprogram_Body | N_Task_Body =>
843 Traverse_Subprogram_Or_Task_Body (Lu);
845 when N_Subprogram_Declaration =>
846 Traverse_Subprogram_Declaration (Lu);
848 when N_Package_Declaration =>
849 Traverse_Package_Declaration (Lu);
851 when N_Package_Body =>
852 Traverse_Package_Body (Lu);
854 when N_Generic_Package_Declaration =>
855 Traverse_Generic_Package_Declaration (Lu);
857 when N_Generic_Instantiation =>
858 Traverse_Generic_Instantiation (Lu);
862 -- All other cases of compilation units (e.g. renamings), generate
863 -- no SCO information.
868 -- Make entry for new unit in unit tables, we will fill in the file
869 -- name and dependency numbers later.
871 SCO_Unit_Table.Append (
875 To => SCO_Table.Last));
877 SCO_Unit_Number_Table.Append (U);
880 -----------------------
881 -- Set_SCO_Condition --
882 -----------------------
884 procedure Set_SCO_Condition (Cond : Node_Id; Val : Boolean) is
885 Orig : constant Node_Id := Original_Node (Cond);
890 Constant_Condition_Code : constant array (Boolean) of Character :=
891 (False => 'f', True => 't');
893 Sloc_Range (Orig, Start, Dummy);
894 Index := Condition_Pragma_Hash_Table.Get (Start);
896 -- The test here for zero is to deal with possible previous errors
899 pragma Assert (SCO_Table.Table (Index).C1 = ' ');
900 SCO_Table.Table (Index).C2 := Constant_Condition_Code (Val);
902 end Set_SCO_Condition;
904 ----------------------------
905 -- Set_SCO_Pragma_Enabled --
906 ----------------------------
908 procedure Set_SCO_Pragma_Enabled (Loc : Source_Ptr) is
912 -- Note: the reason we use the Sloc value as the key is that in the
913 -- generic case, the call to this procedure is made on a copy of the
914 -- original node, so we can't use the Node_Id value.
916 Index := Condition_Pragma_Hash_Table.Get (Loc);
918 -- The test here for zero is to deal with possible previous errors
922 T : SCO_Table_Entry renames SCO_Table.Table (Index);
925 -- Called multiple times for the same sloc (need to allow for
928 pragma Assert (T.C1 = 'S'
930 (T.C2 = 'p' or else T.C2 = 'P'));
934 end Set_SCO_Pragma_Enabled;
936 ---------------------
937 -- Set_Table_Entry --
938 ---------------------
940 procedure Set_Table_Entry
946 Pragma_Sloc : Source_Ptr := No_Location;
947 Pragma_Name : Pragma_Id := Unknown_Pragma)
949 function To_Source_Location (S : Source_Ptr) return Source_Location;
950 -- Converts Source_Ptr value to Source_Location (line/col) format
952 ------------------------
953 -- To_Source_Location --
954 ------------------------
956 function To_Source_Location (S : Source_Ptr) return Source_Location is
958 if S = No_Location then
959 return No_Source_Location;
962 (Line => Get_Logical_Line_Number (S),
963 Col => Get_Column_Number (S));
965 end To_Source_Location;
967 -- Start of processing for Set_Table_Entry
973 From => To_Source_Location (From),
974 To => To_Source_Location (To),
976 Pragma_Sloc => Pragma_Sloc,
977 Pragma_Name => Pragma_Name));
980 -----------------------------------------
981 -- Traverse_Declarations_Or_Statements --
982 -----------------------------------------
984 -- Tables used by Traverse_Declarations_Or_Statements for temporarily
985 -- holding statement and decision entries. These are declared globally
986 -- since they are shared by recursive calls to this procedure.
988 type SC_Entry is record
994 -- Used to store a single entry in the following table, From:To represents
995 -- the range of entries in the CS line entry, and typ is the type, with
996 -- space meaning that no type letter will accompany the entry.
998 package SC is new Table.Table (
999 Table_Component_Type => SC_Entry,
1000 Table_Index_Type => Nat,
1001 Table_Low_Bound => 1,
1002 Table_Initial => 1000,
1003 Table_Increment => 200,
1004 Table_Name => "SCO_SC");
1005 -- Used to store statement components for a CS entry to be output
1006 -- as a result of the call to this procedure. SC.Last is the last
1007 -- entry stored, so the current statement sequence is represented
1008 -- by SC_Array (SC_First .. SC.Last), where SC_First is saved on
1009 -- entry to each recursive call to the routine.
1011 -- Extend_Statement_Sequence adds an entry to this array, and then
1012 -- Set_Statement_Entry clears the entries starting with SC_First,
1013 -- copying these entries to the main SCO output table. The reason that
1014 -- we do the temporary caching of results in this array is that we want
1015 -- the SCO table entries for a given CS line to be contiguous, and the
1016 -- processing may output intermediate entries such as decision entries.
1018 type SD_Entry is record
1024 -- Used to store a single entry in the following table. Nod is the node to
1025 -- be searched for decisions for the case of Process_Decisions_Defer with a
1026 -- node argument (with Lst set to No_List. Lst is the list to be searched
1027 -- for decisions for the case of Process_Decisions_Defer with a List
1028 -- argument (in which case Nod is set to Empty). Plo is the sloc of the
1029 -- enclosing pragma, if any.
1031 package SD is new Table.Table (
1032 Table_Component_Type => SD_Entry,
1033 Table_Index_Type => Nat,
1034 Table_Low_Bound => 1,
1035 Table_Initial => 1000,
1036 Table_Increment => 200,
1037 Table_Name => "SCO_SD");
1038 -- Used to store possible decision information. Instead of calling the
1039 -- Process_Decisions procedures directly, we call Process_Decisions_Defer,
1040 -- which simply stores the arguments in this table. Then when we clear
1041 -- out a statement sequence using Set_Statement_Entry, after generating
1042 -- the CS lines for the statements, the entries in this table result in
1043 -- calls to Process_Decision. The reason for doing things this way is to
1044 -- ensure that decisions are output after the CS line for the statements
1045 -- in which the decisions occur.
1047 procedure Traverse_Declarations_Or_Statements
1049 D : Dominant_Info := No_Dominant;
1050 P : Node_Id := Empty)
1052 Current_Dominant : Dominant_Info := D;
1053 -- Dominance information for the current basic block
1055 Current_Test : Node_Id;
1056 -- Conditional node (N_If_Statement or N_Elsiif being processed
1060 SC_First : constant Nat := SC.Last + 1;
1061 SD_First : constant Nat := SD.Last + 1;
1062 -- Record first entries used in SC/SD at this recursive level
1064 procedure Extend_Statement_Sequence (N : Node_Id; Typ : Character);
1065 -- Extend the current statement sequence to encompass the node N. Typ
1066 -- is the letter that identifies the type of statement/declaration that
1067 -- is being added to the sequence.
1069 procedure Set_Statement_Entry;
1070 -- Output CS entries for all statements saved in table SC, and end the
1071 -- current CS sequence.
1073 procedure Process_Decisions_Defer (N : Node_Id; T : Character);
1074 pragma Inline (Process_Decisions_Defer);
1075 -- This routine is logically the same as Process_Decisions, except that
1076 -- the arguments are saved in the SD table, for later processing when
1077 -- Set_Statement_Entry is called, which goes through the saved entries
1078 -- making the corresponding calls to Process_Decision.
1080 procedure Process_Decisions_Defer (L : List_Id; T : Character);
1081 pragma Inline (Process_Decisions_Defer);
1082 -- Same case for list arguments, deferred call to Process_Decisions
1084 procedure Traverse_One (N : Node_Id);
1085 -- Traverse one declaration or statement
1087 -------------------------
1088 -- Set_Statement_Entry --
1089 -------------------------
1091 procedure Set_Statement_Entry is
1092 SC_Last : constant Int := SC.Last;
1093 SD_Last : constant Int := SD.Last;
1096 -- Output statement entries from saved entries in SC table
1098 for J in SC_First .. SC_Last loop
1099 if J = SC_First then
1101 if Current_Dominant /= No_Dominant then
1103 From, To : Source_Ptr;
1105 Sloc_Range (Current_Dominant.N, From, To);
1106 if Current_Dominant.K /= 'E' then
1111 C2 => Current_Dominant.K,
1115 Pragma_Sloc => No_Location,
1116 Pragma_Name => Unknown_Pragma);
1122 SCE : SC_Entry renames SC.Table (J);
1123 Pragma_Sloc : Source_Ptr := No_Location;
1124 Pragma_Name : Pragma_Id := Unknown_Pragma;
1126 -- For the case of a statement SCO for a pragma controlled by
1127 -- Set_SCO_Pragma_Enabled, set Pragma_Sloc so that the SCO (and
1128 -- those of any nested decision) is emitted only if the pragma
1131 if SCE.Typ = 'p' then
1132 Pragma_Sloc := SCE.From;
1133 Condition_Pragma_Hash_Table.Set
1134 (Pragma_Sloc, SCO_Table.Last + 1);
1135 Pragma_Name := Get_Pragma_Id (Sinfo.Pragma_Name (SCE.N));
1137 elsif SCE.Typ = 'P' then
1138 Pragma_Name := Get_Pragma_Id (Sinfo.Pragma_Name (SCE.N));
1146 Last => (J = SC_Last),
1147 Pragma_Sloc => Pragma_Sloc,
1148 Pragma_Name => Pragma_Name);
1152 -- Last statement of basic block, if present, becomes new current
1155 if SC_Last >= SC_First then
1156 Current_Dominant := ('S', SC.Table (SC_Last).N);
1159 -- Clear out used section of SC table
1161 SC.Set_Last (SC_First - 1);
1163 -- Output any embedded decisions
1165 for J in SD_First .. SD_Last loop
1167 SDE : SD_Entry renames SD.Table (J);
1169 if Present (SDE.Nod) then
1170 Process_Decisions (SDE.Nod, SDE.Typ, SDE.Plo);
1172 Process_Decisions (SDE.Lst, SDE.Typ, SDE.Plo);
1177 -- Clear out used section of SD table
1179 SD.Set_Last (SD_First - 1);
1180 end Set_Statement_Entry;
1182 -------------------------------
1183 -- Extend_Statement_Sequence --
1184 -------------------------------
1186 procedure Extend_Statement_Sequence (N : Node_Id; Typ : Character) is
1190 To_Node : Node_Id := Empty;
1193 Sloc_Range (N, F, T);
1196 when N_Accept_Statement =>
1197 if Present (Parameter_Specifications (N)) then
1198 To_Node := Last (Parameter_Specifications (N));
1199 elsif Present (Entry_Index (N)) then
1200 To_Node := Entry_Index (N);
1203 when N_Case_Statement =>
1204 To_Node := Expression (N);
1206 when N_If_Statement | N_Elsif_Part =>
1207 To_Node := Condition (N);
1209 when N_Extended_Return_Statement =>
1210 To_Node := Last (Return_Object_Declarations (N));
1212 when N_Loop_Statement =>
1213 To_Node := Iteration_Scheme (N);
1215 when N_Selective_Accept |
1216 N_Timed_Entry_Call |
1217 N_Conditional_Entry_Call |
1218 N_Asynchronous_Select =>
1226 if Present (To_Node) then
1227 Sloc_Range (To_Node, Dummy, T);
1230 SC.Append ((N, F, T, Typ));
1231 end Extend_Statement_Sequence;
1233 -----------------------------
1234 -- Process_Decisions_Defer --
1235 -----------------------------
1237 procedure Process_Decisions_Defer (N : Node_Id; T : Character) is
1239 SD.Append ((N, No_List, T, Current_Pragma_Sloc));
1240 end Process_Decisions_Defer;
1242 procedure Process_Decisions_Defer (L : List_Id; T : Character) is
1244 SD.Append ((Empty, L, T, Current_Pragma_Sloc));
1245 end Process_Decisions_Defer;
1251 procedure Traverse_One (N : Node_Id) is
1253 -- Initialize or extend current statement sequence. Note that for
1254 -- special cases such as IF and Case statements we will modify
1255 -- the range to exclude internal statements that should not be
1256 -- counted as part of the current statement sequence.
1260 -- Package declaration
1262 when N_Package_Declaration =>
1263 Set_Statement_Entry;
1264 Traverse_Package_Declaration (N);
1266 -- Generic package declaration
1268 when N_Generic_Package_Declaration =>
1269 Set_Statement_Entry;
1270 Traverse_Generic_Package_Declaration (N);
1274 when N_Package_Body =>
1275 Set_Statement_Entry;
1276 Traverse_Package_Body (N);
1278 -- Subprogram declaration
1280 when N_Subprogram_Declaration =>
1281 Process_Decisions_Defer
1282 (Parameter_Specifications (Specification (N)), 'X');
1284 -- Generic subprogram declaration
1286 when N_Generic_Subprogram_Declaration =>
1287 Process_Decisions_Defer
1288 (Generic_Formal_Declarations (N), 'X');
1289 Process_Decisions_Defer
1290 (Parameter_Specifications (Specification (N)), 'X');
1292 -- Task or subprogram body
1294 when N_Task_Body | N_Subprogram_Body =>
1295 Set_Statement_Entry;
1296 Traverse_Subprogram_Or_Task_Body (N);
1300 when N_Entry_Body =>
1302 Cond : constant Node_Id :=
1303 Condition (Entry_Body_Formal_Part (N));
1305 Inner_Dominant : Dominant_Info := No_Dominant;
1308 Set_Statement_Entry;
1310 if Present (Cond) then
1311 Process_Decisions_Defer (Cond, 'G');
1313 -- For an entry body with a barrier, the entry body
1314 -- is dominanted by a True evaluation of the barrier.
1316 Inner_Dominant := ('T', N);
1319 Traverse_Subprogram_Or_Task_Body (N, Inner_Dominant);
1324 when N_Protected_Body =>
1325 Set_Statement_Entry;
1326 Traverse_Protected_Body (N);
1328 -- Exit statement, which is an exit statement in the SCO sense,
1329 -- so it is included in the current statement sequence, but
1330 -- then it terminates this sequence. We also have to process
1331 -- any decisions in the exit statement expression.
1333 when N_Exit_Statement =>
1334 Extend_Statement_Sequence (N, ' ');
1335 Process_Decisions_Defer (Condition (N), 'E');
1336 Set_Statement_Entry;
1338 -- If condition is present, then following statement is
1339 -- only executed if the condition evaluates to False.
1341 if Present (Condition (N)) then
1342 Current_Dominant := ('F', N);
1344 Current_Dominant := No_Dominant;
1347 -- Label, which breaks the current statement sequence, but the
1348 -- label itself is not included in the next statement sequence,
1349 -- since it generates no code.
1352 Set_Statement_Entry;
1353 Current_Dominant := No_Dominant;
1355 -- Block statement, which breaks the current statement sequence
1357 when N_Block_Statement =>
1358 Set_Statement_Entry;
1359 Traverse_Declarations_Or_Statements
1360 (L => Declarations (N),
1361 D => Current_Dominant);
1362 Traverse_Handled_Statement_Sequence
1363 (N => Handled_Statement_Sequence (N),
1364 D => Current_Dominant);
1366 -- If statement, which breaks the current statement sequence,
1367 -- but we include the condition in the current sequence.
1369 when N_If_Statement =>
1371 Extend_Statement_Sequence (N, 'I');
1372 Process_Decisions_Defer (Condition (N), 'I');
1373 Set_Statement_Entry;
1375 -- Now we traverse the statements in the THEN part
1377 Traverse_Declarations_Or_Statements
1378 (L => Then_Statements (N),
1381 -- Loop through ELSIF parts if present
1383 if Present (Elsif_Parts (N)) then
1385 Saved_Dominant : constant Dominant_Info :=
1388 Elif : Node_Id := First (Elsif_Parts (N));
1391 while Present (Elif) loop
1393 -- An Elsif is executed only if the previous test
1394 -- got a FALSE outcome.
1396 Current_Dominant := ('F', Current_Test);
1398 -- Now update current test information
1400 Current_Test := Elif;
1402 -- We generate a statement sequence for the
1403 -- construct "ELSIF condition", so that we have
1404 -- a statement for the resulting decisions.
1406 Extend_Statement_Sequence (Elif, 'I');
1407 Process_Decisions_Defer (Condition (Elif), 'I');
1408 Set_Statement_Entry;
1410 -- An ELSIF part is never guaranteed to have
1411 -- been executed, following statements are only
1412 -- dominated by the initial IF statement.
1414 Current_Dominant := Saved_Dominant;
1416 -- Traverse the statements in the ELSIF
1418 Traverse_Declarations_Or_Statements
1419 (L => Then_Statements (Elif),
1426 -- Finally traverse the ELSE statements if present
1428 Traverse_Declarations_Or_Statements
1429 (L => Else_Statements (N),
1430 D => ('F', Current_Test));
1432 -- CASE statement, which breaks the current statement sequence,
1433 -- but we include the expression in the current sequence.
1435 when N_Case_Statement =>
1436 Extend_Statement_Sequence (N, 'C');
1437 Process_Decisions_Defer (Expression (N), 'X');
1438 Set_Statement_Entry;
1440 -- Process case branches, all of which are dominated by the
1446 Alt := First (Alternatives (N));
1447 while Present (Alt) loop
1448 Traverse_Declarations_Or_Statements
1449 (L => Statements (Alt),
1450 D => Current_Dominant);
1457 when N_Accept_Statement =>
1458 Extend_Statement_Sequence (N, 'A');
1459 Set_Statement_Entry;
1461 -- Process sequence of statements, dominant is the ACCEPT
1464 Traverse_Handled_Statement_Sequence
1465 (N => Handled_Statement_Sequence (N),
1466 D => Current_Dominant);
1470 when N_Selective_Accept =>
1471 Extend_Statement_Sequence (N, 'S');
1472 Set_Statement_Entry;
1474 -- Process alternatives
1479 S_Dom : Dominant_Info;
1482 Alt := First (Select_Alternatives (N));
1483 while Present (Alt) loop
1484 S_Dom := Current_Dominant;
1485 Guard := Condition (Alt);
1487 if Present (Guard) then
1491 Pragma_Sloc => No_Location);
1492 Current_Dominant := ('T', Guard);
1497 Current_Dominant := S_Dom;
1502 Traverse_Declarations_Or_Statements
1503 (L => Else_Statements (N),
1504 D => Current_Dominant);
1506 when N_Timed_Entry_Call | N_Conditional_Entry_Call =>
1507 Extend_Statement_Sequence (N, 'S');
1508 Set_Statement_Entry;
1510 -- Process alternatives
1512 Traverse_One (Entry_Call_Alternative (N));
1514 if Nkind (N) = N_Timed_Entry_Call then
1515 Traverse_One (Delay_Alternative (N));
1517 Traverse_Declarations_Or_Statements
1518 (L => Else_Statements (N),
1519 D => Current_Dominant);
1522 when N_Asynchronous_Select =>
1523 Extend_Statement_Sequence (N, 'S');
1524 Set_Statement_Entry;
1526 Traverse_One (Triggering_Alternative (N));
1527 Traverse_Declarations_Or_Statements
1528 (L => Statements (Abortable_Part (N)),
1529 D => Current_Dominant);
1531 when N_Accept_Alternative =>
1532 Traverse_Declarations_Or_Statements
1533 (L => Statements (N),
1534 D => Current_Dominant,
1535 P => Accept_Statement (N));
1537 when N_Entry_Call_Alternative =>
1538 Traverse_Declarations_Or_Statements
1539 (L => Statements (N),
1540 D => Current_Dominant,
1541 P => Entry_Call_Statement (N));
1543 when N_Delay_Alternative =>
1544 Traverse_Declarations_Or_Statements
1545 (L => Statements (N),
1546 D => Current_Dominant,
1547 P => Delay_Statement (N));
1549 when N_Triggering_Alternative =>
1550 Traverse_Declarations_Or_Statements
1551 (L => Statements (N),
1552 D => Current_Dominant,
1553 P => Triggering_Statement (N));
1555 when N_Terminate_Alternative =>
1556 Extend_Statement_Sequence (N, ' ');
1557 Set_Statement_Entry;
1559 -- Unconditional exit points, which are included in the current
1560 -- statement sequence, but then terminate it
1562 when N_Requeue_Statement |
1564 N_Raise_Statement =>
1565 Extend_Statement_Sequence (N, ' ');
1566 Set_Statement_Entry;
1567 Current_Dominant := No_Dominant;
1569 -- Simple return statement. which is an exit point, but we
1570 -- have to process the return expression for decisions.
1572 when N_Simple_Return_Statement =>
1573 Extend_Statement_Sequence (N, ' ');
1574 Process_Decisions_Defer (Expression (N), 'X');
1575 Set_Statement_Entry;
1576 Current_Dominant := No_Dominant;
1578 -- Extended return statement
1580 when N_Extended_Return_Statement =>
1581 Extend_Statement_Sequence (N, 'R');
1582 Process_Decisions_Defer
1583 (Return_Object_Declarations (N), 'X');
1584 Set_Statement_Entry;
1586 Traverse_Handled_Statement_Sequence
1587 (N => Handled_Statement_Sequence (N),
1588 D => Current_Dominant);
1590 Current_Dominant := No_Dominant;
1592 -- Loop ends the current statement sequence, but we include
1593 -- the iteration scheme if present in the current sequence.
1594 -- But the body of the loop starts a new sequence, since it
1595 -- may not be executed as part of the current sequence.
1597 when N_Loop_Statement =>
1599 ISC : constant Node_Id := Iteration_Scheme (N);
1600 Inner_Dominant : Dominant_Info := No_Dominant;
1603 if Present (ISC) then
1605 -- If iteration scheme present, extend the current
1606 -- statement sequence to include the iteration scheme
1607 -- and process any decisions it contains.
1611 if Present (Condition (ISC)) then
1612 Extend_Statement_Sequence (N, 'W');
1613 Process_Decisions_Defer (Condition (ISC), 'W');
1615 -- Set more specific dominant for inner statements
1616 -- (the control sloc for the decision is that of
1617 -- the WHILE token).
1619 Inner_Dominant := ('T', ISC);
1624 Extend_Statement_Sequence (N, 'F');
1625 Process_Decisions_Defer
1626 (Loop_Parameter_Specification (ISC), 'X');
1630 Set_Statement_Entry;
1632 if Inner_Dominant = No_Dominant then
1633 Inner_Dominant := Current_Dominant;
1636 Traverse_Declarations_Or_Statements
1637 (L => Statements (N),
1638 D => Inner_Dominant);
1645 -- Record sloc of pragma (pragmas don't nest)
1647 pragma Assert (Current_Pragma_Sloc = No_Location);
1648 Current_Pragma_Sloc := Sloc (N);
1650 -- Processing depends on the kind of pragma
1653 Nam : constant Name_Id := Pragma_Name (N);
1655 First (Pragma_Argument_Associations (N));
1663 Name_Postcondition =>
1665 -- For Assert/Check/Precondition/Postcondition, we
1666 -- must generate a P entry for the decision. Note
1667 -- that this is done unconditionally at this stage.
1668 -- Output for disabled pragmas is suppressed later
1669 -- on when we output the decision line in Put_SCOs,
1670 -- depending on setting by Set_SCO_Pragma_Enabled.
1672 if Nam = Name_Check then
1676 Process_Decisions_Defer (Expression (Arg), 'P');
1680 if Present (Arg) and then Present (Next (Arg)) then
1682 -- Case of a dyadic pragma Debug: first argument
1683 -- is a P decision, any nested decision in the
1684 -- second argument is an X decision.
1686 Process_Decisions_Defer (Expression (Arg), 'P');
1690 Process_Decisions_Defer (Expression (Arg), 'X');
1693 -- For all other pragmas, we generate decision entries
1694 -- for any embedded expressions, and the pragma is
1698 Process_Decisions_Defer (N, 'X');
1702 -- Add statement SCO
1704 Extend_Statement_Sequence (N, Typ);
1706 Current_Pragma_Sloc := No_Location;
1709 -- Object declaration. Ignored if Prev_Ids is set, since the
1710 -- parser generates multiple instances of the whole declaration
1711 -- if there is more than one identifier declared, and we only
1712 -- want one entry in the SCO's, so we take the first, for which
1713 -- Prev_Ids is False.
1715 when N_Object_Declaration =>
1716 if not Prev_Ids (N) then
1717 Extend_Statement_Sequence (N, 'o');
1719 if Has_Decision (N) then
1720 Process_Decisions_Defer (N, 'X');
1724 -- All other cases, which extend the current statement sequence
1725 -- but do not terminate it, even if they have nested decisions.
1729 -- Determine required type character code, or ASCII.NUL if
1730 -- no SCO should be generated for this node.
1737 when N_Full_Type_Declaration |
1738 N_Incomplete_Type_Declaration |
1739 N_Private_Type_Declaration |
1740 N_Private_Extension_Declaration =>
1743 when N_Subtype_Declaration =>
1746 when N_Renaming_Declaration =>
1749 when N_Generic_Instantiation =>
1752 when N_Representation_Clause |
1753 N_Use_Package_Clause |
1754 N_Use_Type_Clause =>
1761 if Typ /= ASCII.NUL then
1762 Extend_Statement_Sequence (N, Typ);
1766 -- Process any embedded decisions
1768 if Has_Decision (N) then
1769 Process_Decisions_Defer (N, 'X');
1775 -- Start of processing for Traverse_Declarations_Or_Statements
1782 if Is_Non_Empty_List (L) then
1784 -- Loop through statements or declarations
1787 while Present (N) loop
1792 Set_Statement_Entry;
1794 end Traverse_Declarations_Or_Statements;
1796 ------------------------------------
1797 -- Traverse_Generic_Instantiation --
1798 ------------------------------------
1800 procedure Traverse_Generic_Instantiation (N : Node_Id) is
1805 -- First we need a statement entry to cover the instantiation
1807 Sloc_Range (N, First, Last);
1815 -- Now output any embedded decisions
1817 Process_Decisions (N, 'X', No_Location);
1818 end Traverse_Generic_Instantiation;
1820 ------------------------------------------
1821 -- Traverse_Generic_Package_Declaration --
1822 ------------------------------------------
1824 procedure Traverse_Generic_Package_Declaration (N : Node_Id) is
1826 Process_Decisions (Generic_Formal_Declarations (N), 'X', No_Location);
1827 Traverse_Package_Declaration (N);
1828 end Traverse_Generic_Package_Declaration;
1830 -----------------------------------------
1831 -- Traverse_Handled_Statement_Sequence --
1832 -----------------------------------------
1834 procedure Traverse_Handled_Statement_Sequence
1836 D : Dominant_Info := No_Dominant)
1841 -- For package bodies without a statement part, the parser adds an empty
1842 -- one, to normalize the representation. The null statement therein,
1843 -- which does not come from source, does not get a SCO.
1845 if Present (N) and then Comes_From_Source (N) then
1846 Traverse_Declarations_Or_Statements (Statements (N), D);
1848 if Present (Exception_Handlers (N)) then
1849 Handler := First (Exception_Handlers (N));
1850 while Present (Handler) loop
1851 Traverse_Declarations_Or_Statements
1852 (L => Statements (Handler),
1853 D => ('E', Handler));
1858 end Traverse_Handled_Statement_Sequence;
1860 ---------------------------
1861 -- Traverse_Package_Body --
1862 ---------------------------
1864 procedure Traverse_Package_Body (N : Node_Id) is
1866 Traverse_Declarations_Or_Statements (Declarations (N));
1867 Traverse_Handled_Statement_Sequence (Handled_Statement_Sequence (N));
1868 end Traverse_Package_Body;
1870 ----------------------------------
1871 -- Traverse_Package_Declaration --
1872 ----------------------------------
1874 procedure Traverse_Package_Declaration (N : Node_Id) is
1875 Spec : constant Node_Id := Specification (N);
1877 Traverse_Declarations_Or_Statements (Visible_Declarations (Spec));
1878 Traverse_Declarations_Or_Statements (Private_Declarations (Spec));
1879 end Traverse_Package_Declaration;
1881 -----------------------------
1882 -- Traverse_Protected_Body --
1883 -----------------------------
1885 procedure Traverse_Protected_Body (N : Node_Id) is
1887 Traverse_Declarations_Or_Statements (Declarations (N));
1888 end Traverse_Protected_Body;
1890 --------------------------------------
1891 -- Traverse_Subprogram_Or_Task_Body --
1892 --------------------------------------
1894 procedure Traverse_Subprogram_Or_Task_Body
1896 D : Dominant_Info := No_Dominant)
1899 Traverse_Declarations_Or_Statements (Declarations (N), D);
1900 Traverse_Handled_Statement_Sequence (Handled_Statement_Sequence (N), D);
1901 end Traverse_Subprogram_Or_Task_Body;
1903 -------------------------------------
1904 -- Traverse_Subprogram_Declaration --
1905 -------------------------------------
1907 procedure Traverse_Subprogram_Declaration (N : Node_Id) is
1908 ADN : constant Node_Id := Aux_Decls_Node (Parent (N));
1910 Traverse_Declarations_Or_Statements (Config_Pragmas (ADN));
1911 Traverse_Declarations_Or_Statements (Declarations (ADN));
1912 Traverse_Declarations_Or_Statements (Pragmas_After (ADN));
1913 end Traverse_Subprogram_Declaration;