OSDN Git Service

* exp_disp.adb (Make_Tags): Mark the imported view of dispatch tables
[pf3gnuchains/gcc-fork.git] / gcc / ada / par_sco.adb
index 663959d..82ab9d6 100644 (file)
@@ -27,11 +27,15 @@ with Atree;    use Atree;
 with Debug;    use Debug;
 with Lib;      use Lib;
 with Lib.Util; use Lib.Util;
+with Namet;    use Namet;
 with Nlists;   use Nlists;
 with Opt;      use Opt;
 with Output;   use Output;
+with Put_SCOs;
+with SCOs;     use SCOs;
 with Sinfo;    use Sinfo;
 with Sinput;   use Sinput;
+with Snames;   use Snames;
 with Table;
 
 with GNAT.HTable;      use GNAT.HTable;
@@ -39,99 +43,25 @@ with GNAT.Heap_Sort_G;
 
 package body Par_SCO is
 
-   ---------------
-   -- SCO_Table --
-   ---------------
-
-   --  Internal table used to store recorded SCO values. Table is populated by
-   --  calls to SCO_Record, and entries may be modified by Set_SCO_Condition.
-
-   type SCO_Table_Entry is record
-      From : Source_Ptr;
-      To   : Source_Ptr;
-      C1   : Character;
-      C2   : Character;
-      Last : Boolean;
-   end record;
-
-   package SCO_Table is new Table.Table (
-     Table_Component_Type => SCO_Table_Entry,
-     Table_Index_Type     => Nat,
-     Table_Low_Bound      => 1,
-     Table_Initial        => 500,
-     Table_Increment      => 300,
-     Table_Name           => "SCO_Table_Entry");
-
-   --  The SCO_Table_Entry values appear as follows:
-
-   --    Statements
-   --      C1   = 'S'
-   --      C2   = ' '
-   --      From = starting sloc
-   --      To   = ending sloc
-   --      Last = unused
-
-   --    Exit
-   --      C1   = 'T'
-   --      C2   = ' '
-   --      From = starting sloc
-   --      To   = ending sloc
-   --      Last = unused
-
-   --    Simple Decision
-   --      C1   = 'I', 'E', 'W', 'X' (if/exit/while/expression)
-   --      C2   = 'c', 't', or 'f'
-   --      From = starting sloc
-   --      To   = ending sloc
-   --      Last = True
-
-   --    Complex Decision
-   --      C1   = 'I', 'E', 'W', 'X' (if/exit/while/expression)
-   --      C2   = ' '
-   --      From = No_Location
-   --      To   = No_Location
-   --      Last = False
-
-   --    Operator
-   --      C1   = '!', '^', '&', '|'
-   --      C2   = ' '
-   --      From = No_Location
-   --      To   = No_Location
-   --      Last = False
-
-   --    Element
-   --      C1   = ' '
-   --      C2   = 'c', 't', or 'f' (condition/true/false)
-   --      From = starting sloc
-   --      To   = ending sloc
-   --      Last = False for all but the last entry, True for last entry
-
-   --    Note: the sequence starting with a decision, and continuing with
-   --    operators and elements up to and including the first one labeled with
-   --    Last=True, indicate the sequence to be output for a complex decision
-   --    on a single CD decision line.
-
-   ----------------
-   -- Unit Table --
-   ----------------
+   -----------------------
+   -- Unit Number Table --
+   -----------------------
 
-   --  This table keeps track of the units and the corresponding starting and
-   --  ending indexes (From, To) in the SCO table. Note that entry zero is
-   --  unused, it is for convenience in calling the sort routine.
+   --  This table parallels the SCO_Unit_Table, keeping track of the unit
+   --  numbers corresponding to the entries made in this table, so that before
+   --  writing out the SCO information to the ALI file, we can fill in the
+   --  proper dependency numbers and file names.
 
-   type SCO_Unit_Table_Entry is record
-      Unit : Unit_Number_Type;
-      From : Nat;
-      To   : Nat;
-   end record;
+   --  Note that the zero'th entry is here for convenience in sorting the
+   --  table, the real lower bound is 1.
 
-   package SCO_Unit_Table is new Table.Table (
-     Table_Component_Type => SCO_Unit_Table_Entry,
-     Table_Index_Type     => Int,
-     Table_Low_Bound      => 0,
+   package SCO_Unit_Number_Table is new Table.Table (
+     Table_Component_Type => Unit_Number_Type,
+     Table_Index_Type     => SCO_Unit_Index,
+     Table_Low_Bound      => 0, -- see note above on sort
      Table_Initial        => 20,
      Table_Increment      => 200,
-     Table_Name           => "SCO_Unit_Table_Entry");
+     Table_Name           => "SCO_Unit_Number_Entry");
 
    --------------------------
    -- Condition Hash Table --
@@ -166,15 +96,16 @@ package body Par_SCO is
 
    function Is_Logical_Operator (N : Node_Id) return Boolean;
    --  N is the node for a subexpression. This procedure just tests N to see
-   --  if it is a logical operator (including short circuit conditions) and
-   --  returns True if so, False otherwise, it does no other processing.
+   --  if it is a logical operator (including short circuit conditions, but
+   --  excluding OR and AND) and returns True if so, False otherwise, it does
+   --  no other processing.
 
    procedure Process_Decisions (N : Node_Id; T : Character);
    --  If N is Empty, has no effect. Otherwise scans the tree for the node N,
-   --  to output any decisions it contains. T is one of IEWX (for context of
-   --  expresion: if/while/when-exit/expression). If T is other than X, then
-   --  the node is always a decision a decision is always present (at the very
-   --  least a simple decision is present at the top level).
+   --  to output any decisions it contains. T is one of IEPWX (for context of
+   --  expresion: if/exit when/pragma/while/expression). If T is other than X,
+   --  then a decision is always present (at the very least a simple decision
+   --  is present at the top level).
 
    procedure Process_Decisions (L : List_Id; T : Character);
    --  Calls above procedure for each element of the list L
@@ -195,8 +126,8 @@ package body Par_SCO is
    procedure Traverse_Subprogram_Body             (N : Node_Id);
    --  Traverse the corresponding construct, generating SCO table entries
 
-   procedure dsco;
-   --  Debug routine to dump SCO table
+   procedure Write_SCOs_To_ALI_File is new Put_SCOs;
+   --  Write SCO information to the ALI file using routines in Lib.Util
 
    ----------
    -- dsco --
@@ -204,46 +135,97 @@ package body Par_SCO is
 
    procedure dsco is
    begin
+      --  Dump SCO unit table
+
       Write_Line ("SCO Unit Table");
       Write_Line ("--------------");
 
-      for Index in SCO_Unit_Table.First .. SCO_Unit_Table.Last loop
-         Write_Str ("  ");
-         Write_Int (Index);
-         Write_Str (".  Unit = ");
-         Write_Int (Int (SCO_Unit_Table.Table (Index).Unit));
-         Write_Str ("  From = ");
-         Write_Int (Int (SCO_Unit_Table.Table (Index).From));
-         Write_Str ("  To = ");
-         Write_Int (Int (SCO_Unit_Table.Table (Index).To));
-         Write_Eol;
+      for Index in 1 .. SCO_Unit_Table.Last loop
+         declare
+            UTE : SCO_Unit_Table_Entry renames SCO_Unit_Table.Table (Index);
+
+         begin
+            Write_Str ("  ");
+            Write_Int (Int (Index));
+            Write_Str (".  Dep_Num = ");
+            Write_Int (Int (UTE.Dep_Num));
+            Write_Str ("  From = ");
+            Write_Int (Int (UTE.From));
+            Write_Str ("  To = ");
+            Write_Int (Int (UTE.To));
+
+            Write_Str ("  File_Name = """);
+
+            if UTE.File_Name /= null then
+               Write_Str (UTE.File_Name.all);
+            end if;
+
+            Write_Char ('"');
+            Write_Eol;
+         end;
       end loop;
 
+      --  Dump SCO Unit number table if it contains any entries
+
+      if SCO_Unit_Number_Table.Last >= 1 then
+         Write_Eol;
+         Write_Line ("SCO Unit Number Table");
+         Write_Line ("---------------------");
+
+         for Index in 1 .. SCO_Unit_Number_Table.Last loop
+            Write_Str ("  ");
+            Write_Int (Int (Index));
+            Write_Str (". Unit_Number = ");
+            Write_Int (Int (SCO_Unit_Number_Table.Table (Index)));
+            Write_Eol;
+         end loop;
+      end if;
+
+      --  Dump SCO table itself
+
       Write_Eol;
       Write_Line ("SCO Table");
       Write_Line ("---------");
 
-      for Index in SCO_Table.First .. SCO_Table.Last loop
+      for Index in 1 .. SCO_Table.Last loop
          declare
             T : SCO_Table_Entry renames SCO_Table.Table (Index);
 
          begin
-            Write_Str ("  ");
-            Write_Int (Index);
-            Write_Str (".  C1 = '");
-            Write_Char (T.C1);
-            Write_Str ("' C2 = '");
-            Write_Char (T.C2);
-            Write_Str ("' From = ");
-            Write_Location (T.From);
-            Write_Str ("  To = ");
-            Write_Location (T.To);
-            Write_Str (" Last = ");
+            Write_Str  ("  ");
+            Write_Int  (Index);
+            Write_Char ('.');
+
+            if T.C1 /= ' ' then
+               Write_Str  ("  C1 = '");
+               Write_Char (T.C1);
+               Write_Char (''');
+            end if;
+
+            if T.C2 /= ' ' then
+               Write_Str  ("  C2 = '");
+               Write_Char (T.C2);
+               Write_Char (''');
+            end if;
+
+            if T.From /= No_Source_Location then
+               Write_Str ("  From = ");
+               Write_Int (Int (T.From.Line));
+               Write_Char (':');
+               Write_Int (Int (T.From.Col));
+            end if;
+
+            if T.To /= No_Source_Location then
+               Write_Str ("  To = ");
+               Write_Int (Int (T.To.Line));
+               Write_Char (':');
+               Write_Int (Int (T.To.Col));
+            end if;
 
             if T.Last then
-               Write_Str (" True");
+               Write_Str ("  True");
             else
-               Write_Str (" False");
+               Write_Str ("  False");
             end if;
 
             Write_Eol;
@@ -304,9 +286,11 @@ package body Par_SCO is
 
    procedure Initialize is
    begin
-      SCO_Unit_Table.Init;
-      SCO_Unit_Table.Increment_Last;
-      SCO_Table.Init;
+      SCO_Unit_Number_Table.Init;
+
+      --  Set dummy 0'th entry in place for sort
+
+      SCO_Unit_Number_Table.Increment_Last;
    end Initialize;
 
    -------------------------
@@ -315,9 +299,7 @@ package body Par_SCO is
 
    function Is_Logical_Operator (N : Node_Id) return Boolean is
    begin
-      return Nkind_In (N, N_Op_And,
-                          N_Op_Or,
-                          N_Op_Xor,
+      return Nkind_In (N, N_Op_Xor,
                           N_Op_Not,
                           N_And_Then,
                           N_Or_Else);
@@ -380,9 +362,6 @@ package body Par_SCO is
          C : Character;
          L : Node_Id;
 
-         FSloc : Source_Ptr;
-         LSloc : Source_Ptr;
-
       begin
          if No (N) then
             return;
@@ -406,8 +385,7 @@ package body Par_SCO is
                end if;
             end if;
 
-            Sloc_Range (N, FSloc, LSloc);
-            Set_Table_Entry (C, ' ', FSloc, LSloc, False);
+            Set_Table_Entry (C, ' ', No_Location, No_Location, False);
 
             Output_Decision_Operand (L);
             Output_Decision_Operand (Right_Opnd (N));
@@ -458,15 +436,11 @@ package body Par_SCO is
       begin
          case Nkind (N) is
 
-               --  Logical operators and short circuit forms, output table
-               --  entries and then process operands recursively to deal with
-               --  nested conditions.
+               --  Logical operators, output table entries and then process
+               --  operands recursively to deal with nested conditions.
 
             when N_And_Then                    |
                  N_Or_Else                     |
-                 N_Op_And                      |
-                 N_Op_Or                       |
-                 N_Op_Xor                      |
                  N_Op_Not                      =>
 
                declare
@@ -549,42 +523,52 @@ package body Par_SCO is
       Traverse (N);
    end Process_Decisions;
 
-   ----------------
-   -- SCO_Output --
-   ----------------
+   -----------
+   -- pscos --
+   -----------
 
-   procedure SCO_Output is
-      Start : Nat;
-      Stop  : Nat;
-      U     : Unit_Number_Type;
+   procedure pscos is
 
-      procedure Output_Range (From : Source_Ptr; To : Source_Ptr);
-      --  Outputs Sloc range in line:col-line:col format (for now we do not
-      --  worry about generic instantiations???)
+      procedure Write_Info_Char (C : Character) renames Write_Char;
+      --  Write one character;
 
-      ------------------
-      -- Output_Range --
-      ------------------
+      procedure Write_Info_Initiate (Key : Character) renames Write_Char;
+      --  Start new one and write one character;
+
+      procedure Write_Info_Nat (N : Nat);
+      --  Write value of N
+
+      procedure Write_Info_Terminate renames Write_Eol;
+      --  Terminate current line
 
-      procedure Output_Range (From : Source_Ptr; To : Source_Ptr) is
+      --------------------
+      -- Write_Info_Nat --
+      --------------------
+
+      procedure Write_Info_Nat (N : Nat) is
       begin
-         Write_Info_Nat (Int (Get_Logical_Line_Number (From)));
-         Write_Info_Char (':');
-         Write_Info_Nat (Int (Get_Column_Number (From)));
-         Write_Info_Char ('-');
-         Write_Info_Nat (Int (Get_Logical_Line_Number (To)));
-         Write_Info_Char (':');
-         Write_Info_Nat (Int (Get_Column_Number (To)));
-      end Output_Range;
+         Write_Int (N);
+      end Write_Info_Nat;
 
-   --  Start of processing for SCO_Output
+      procedure Debug_Put_SCOs is new Put_SCOs;
+
+      --  Start of processing for pscos
+
+   begin
+      Debug_Put_SCOs;
+   end pscos;
 
+   ----------------
+   -- SCO_Output --
+   ----------------
+
+   procedure SCO_Output is
    begin
       if Debug_Flag_Dot_OO then
          dsco;
       end if;
 
-      --  Sort the unit table
+      --  Sort the unit tables based on dependency numbers
 
       Unit_Table_Sort : declare
 
@@ -600,8 +584,12 @@ package body Par_SCO is
 
          function Lt (Op1, Op2 : Natural) return Boolean is
          begin
-            return Dependency_Num (SCO_Unit_Table.Table (Nat (Op1)).Unit) <
-                   Dependency_Num (SCO_Unit_Table.Table (Nat (Op2)).Unit);
+            return
+              Dependency_Num
+                (SCO_Unit_Number_Table.Table (SCO_Unit_Index (Op1)))
+                     <
+              Dependency_Num
+                (SCO_Unit_Number_Table.Table (SCO_Unit_Index (Op2)));
          end Lt;
 
          ----------
@@ -610,8 +598,10 @@ package body Par_SCO is
 
          procedure Move (From : Natural; To : Natural) is
          begin
-            SCO_Unit_Table.Table (Nat (To)) :=
-              SCO_Unit_Table.Table (Nat (From));
+            SCO_Unit_Table.Table (SCO_Unit_Index (To)) :=
+              SCO_Unit_Table.Table (SCO_Unit_Index (From));
+            SCO_Unit_Number_Table.Table (SCO_Unit_Index (To)) :=
+              SCO_Unit_Number_Table.Table (SCO_Unit_Index (From));
          end Move;
 
          package Sorting is new GNAT.Heap_Sort_G (Move, Lt);
@@ -622,88 +612,23 @@ package body Par_SCO is
          Sorting.Sort (Integer (SCO_Unit_Table.Last));
       end Unit_Table_Sort;
 
-      --  Loop through entries in the unit table
+      --  Loop through entries in the unit table to set file name and
+      --  dependency number entries.
 
       for J in 1 .. SCO_Unit_Table.Last loop
-         U := SCO_Unit_Table.Table (J).Unit;
-
-         --  Output header line preceded by blank line
-
-         Write_Info_Terminate;
-         Write_Info_Initiate ('C');
-         Write_Info_Char (' ');
-         Write_Info_Nat (Dependency_Num (U));
-         Write_Info_Char (' ');
-         Write_Info_Name (Reference_Name (Source_Index (U)));
-         Write_Info_Terminate;
-
-         Start := SCO_Unit_Table.Table (J).From;
-         Stop  := SCO_Unit_Table.Table (J).To;
-
-         --  Loop through relevant entries in SCO table, outputting C lines
-
-         while Start <= Stop loop
-            declare
-               T : SCO_Table_Entry renames SCO_Table.Table (Start);
-
-            begin
-               Write_Info_Initiate ('C');
-               Write_Info_Char (T.C1);
-
-               case T.C1 is
-
-                  --  Statements, exit
-
-                  when 'S' | 'T' =>
-                     Write_Info_Char (' ');
-                     Output_Range (T.From, T.To);
-
-                     --  Decision
-
-                  when 'I' | 'E' | 'W' | 'X' =>
-                     if T.C2 = ' ' then
-                        Start := Start + 1;
-                     end if;
-
-                     --  Loop through table entries for this decision
-
-                     loop
-                        declare
-                           T : SCO_Table_Entry renames SCO_Table.Table (Start);
-
-                        begin
-                           Write_Info_Char (' ');
-
-                           if T.C1 = '!' or else
-                             T.C1 = '^' or else
-                             T.C1 = '&' or else
-                             T.C1 = '|'
-                           then
-                              Write_Info_Char (T.C1);
-
-                           else
-                              Write_Info_Char (T.C2);
-                              Output_Range (T.From, T.To);
-                           end if;
-
-                           exit when T.Last;
-                           Start := Start + 1;
-                        end;
-                     end loop;
-
-                  when others =>
-                     raise Program_Error;
-               end case;
-
-               Write_Info_Terminate;
-            end;
+         declare
+            U   : constant Unit_Number_Type := SCO_Unit_Number_Table.Table (J);
+            UTE : SCO_Unit_Table_Entry renames SCO_Unit_Table.Table (J);
+         begin
+            Get_Name_String (Reference_Name (Source_Index (U)));
+            UTE.File_Name := new String'(Name_Buffer (1 .. Name_Len));
+            UTE.Dep_Num := Dependency_Num (U);
+         end;
+      end loop;
 
-            exit when Start = Stop;
-            Start := Start + 1;
+      --  Now the tables are all setup for output to the ALI file
 
-            pragma Assert (Start <= Stop);
-         end loop;
-      end loop;
+      Write_SCOs_To_ALI_File;
    end SCO_Output;
 
    ----------------
@@ -723,8 +648,8 @@ package body Par_SCO is
 
       --  Ignore call if this unit already recorded
 
-      for J in 1 .. SCO_Unit_Table.Last loop
-         if SCO_Unit_Table.Table (J).Unit = U then
+      for J in 1 .. SCO_Unit_Number_Table.Last loop
+         if U = SCO_Unit_Number_Table.Table (J) then
             return;
          end if;
       end loop;
@@ -763,9 +688,16 @@ package body Par_SCO is
          Process_Decisions (Lu, 'X');
       end if;
 
-      --  Make entry for new unit in unit table
+      --  Make entry for new unit in unit tables, we will fill in the file
+      --  name and dependency numbers later.
+
+      SCO_Unit_Table.Append (
+        (Dep_Num   => 0,
+         File_Name => null,
+         From      => From,
+         To        => SCO_Table.Last));
 
-      SCO_Unit_Table.Append ((Unit => U, From => From, To => SCO_Table.Last));
+      SCO_Unit_Number_Table.Append (U);
    end SCO_Record;
 
    -----------------------
@@ -791,12 +723,33 @@ package body Par_SCO is
       To   : Source_Ptr;
       Last : Boolean)
    is
+      function To_Source_Location (S : Source_Ptr) return Source_Location;
+      --  Converts Source_Ptr value to Source_Location (line/col) format
+
+      ------------------------
+      -- To_Source_Location --
+      ------------------------
+
+      function To_Source_Location (S : Source_Ptr) return Source_Location is
+      begin
+         if S = No_Location then
+            return No_Source_Location;
+         else
+            return
+              (Line => Get_Logical_Line_Number (S),
+               Col  => Get_Column_Number (S));
+         end if;
+      end To_Source_Location;
+
+   --  Start of processing for Set_Table_Entry
+
    begin
-      SCO_Table.Append ((C1   => C1,
-                         C2   => C2,
-                         From => From,
-                         To   => To,
-                         Last => Last));
+      Add_SCO
+        (C1   => C1,
+         C2   => C2,
+         From => To_Source_Location (From),
+         To   => To_Source_Location (To),
+         Last => Last);
    end Set_Table_Entry;
 
    -----------------------------------------
@@ -805,14 +758,46 @@ package body Par_SCO is
 
    procedure Traverse_Declarations_Or_Statements (L : List_Id) is
       N     : Node_Id;
-      Start : Source_Ptr;
       Dummy : Source_Ptr;
-      Stop  : Source_Ptr;
-      From  : Source_Ptr;
-      To    : Source_Ptr;
 
-      Term  : Boolean;
-      --  Set False if current entity terminates statement list
+      type SC_Entry is record
+         From : Source_Ptr;
+         To   : Source_Ptr;
+         Typ  : Character;
+      end record;
+      --  Used to store a single entry in the following array
+
+      SC_Array : array (Nat range 1 .. 10_000) of SC_Entry;
+      SC_Last  : Nat;
+      --  Used to store statement components for a CS entry to be output
+      --  as a result of the call to this procedure. SC_Last is the last
+      --  entry stored, so the current statement sequence is represented
+      --  by SC_Array (1 .. SC_Last). Extend_Statement_Sequence adds an
+      --  entry to this array, and Set_Statement_Entry clears it, copying
+      --  the entries to the main SCO output table. The reason that we do
+      --  the temporary caching of results in this array is that we want
+      --  the SCO table entries for a given CS line to be contiguous, and
+      --  the processing may output intermediate entries such as decision
+      --  entries. Note that the limit of 10_000 here is arbitrary, but does
+      --  not cause any trouble, if we encounter more than 10_000 statements
+      --  we simply break the current CS sequence at that point, which is
+      --  harmless, since this is only used for back annotation and it is
+      --  not critical that back annotation always work in all cases. Anyway
+      --  exceeding 10,000 statements in a basic block is very unlikely.
+
+      procedure Extend_Statement_Sequence (N : Node_Id; Typ : Character);
+      --  Extend the current statement sequence to encompass the node N. Typ
+      --  is the letter that identifies the type of statement/declaration that
+      --  is being added to the sequence.
+
+      procedure Extend_Statement_Sequence
+        (From : Node_Id;
+         To   : Node_Id;
+         Typ  : Character);
+      --  This version extends the current statement sequence with an entry
+      --  that starts with the first token of From, and ends with the last
+      --  token of To. It is used for example in a CASE statement to cover
+      --  the range from the CASE token to the last token of the expression.
 
       procedure Set_Statement_Entry;
       --  If Start is No_Location, does nothing, otherwise outputs a SCO_Table
@@ -826,27 +811,86 @@ package body Par_SCO is
       -------------------------
 
       procedure Set_Statement_Entry is
+         C1   : Character;
+
       begin
-         Term := True;
+         if SC_Last /= 0 then
+            for J in 1 .. SC_Last loop
+               if J = 1 then
+                  C1 := 'S';
+               else
+                  C1 := 's';
+               end if;
 
-         if Start /= No_Location then
-            Set_Table_Entry ('S', ' ', Start, Stop, False);
-            Start := No_Location;
-            Stop  := No_Location;
+               Set_Table_Entry
+                 (C1   => C1,
+                  C2   => SC_Array (J).Typ,
+                  From => SC_Array (J).From,
+                  To   => SC_Array (J).To,
+                  Last => (J = SC_Last));
+            end loop;
+
+            SC_Last := 0;
          end if;
       end Set_Statement_Entry;
 
+      -------------------------------
+      -- Extend_Statement_Sequence --
+      -------------------------------
+
+      procedure Extend_Statement_Sequence (N : Node_Id; Typ : Character) is
+      begin
+         --  Clear out statement sequence if array full
+
+         if SC_Last = SC_Array'Last then
+            Set_Statement_Entry;
+         else
+            SC_Last := SC_Last + 1;
+         end if;
+
+         --  Record new entry
+
+         Sloc_Range
+           (N, SC_Array (SC_Last).From, SC_Array (SC_Last).To);
+         SC_Array (SC_Last).Typ := Typ;
+      end Extend_Statement_Sequence;
+
+      procedure Extend_Statement_Sequence
+        (From : Node_Id;
+         To   : Node_Id;
+         Typ  : Character)
+      is
+      begin
+         --  Clear out statement sequence if array full
+
+         if SC_Last = SC_Array'Last then
+            Set_Statement_Entry;
+         else
+            SC_Last := SC_Last + 1;
+         end if;
+
+         --  Make new entry
+
+         Sloc_Range (From, SC_Array (SC_Last).From, Dummy);
+         Sloc_Range (To, Dummy, SC_Array (SC_Last).To);
+         SC_Array (SC_Last).Typ := Typ;
+      end Extend_Statement_Sequence;
+
    --  Start of processing for Traverse_Declarations_Or_Statements
 
    begin
       if Is_Non_Empty_List (L) then
-         N := First (L);
-         Start := No_Location;
+         SC_Last := 0;
 
          --  Loop through statements or declarations
 
+         N := First (L);
          while Present (N) loop
-            Term := False;
+
+            --  Initialize or extend current statement sequence. Note that for
+            --  special cases such as IF and Case statements we will modify
+            --  the range to exclude internal statements that should not be
+            --  counted as part of the current statement sequence.
 
             case Nkind (N) is
 
@@ -889,23 +933,24 @@ package body Par_SCO is
                   Set_Statement_Entry;
                   Traverse_Subprogram_Body (N);
 
-               --  Exit statement
+               --  Exit statement, which is an exit statement in the SCO sense,
+               --  so it is included in the current statement sequence, but
+               --  then it terminates this sequence. We also have to process
+               --  any decisions in the exit statement expression.
 
                when N_Exit_Statement =>
+                  Extend_Statement_Sequence (N, ' ');
                   Set_Statement_Entry;
                   Process_Decisions (Condition (N), 'E');
 
-                  --  This is an exit point
-
-                  Sloc_Range (N, From, To);
-                  Set_Table_Entry ('T', ' ', From, To, False);
-
-               --  Label (breaks statement sequence)
+               --  Label, which breaks the current statement sequence, but the
+               --  label itself is not included in the next statement sequence,
+               --  since it generates no code.
 
                when N_Label =>
                   Set_Statement_Entry;
 
-               --  Block statement
+               --  Block statement, which breaks the current statement sequence
 
                when N_Block_Statement =>
                   Set_Statement_Entry;
@@ -913,9 +958,11 @@ package body Par_SCO is
                   Traverse_Handled_Statement_Sequence
                     (Handled_Statement_Sequence (N));
 
-               --  If statement
+               --  If statement, which breaks the current statement sequence,
+               --  but we include the condition in the current sequence.
 
                when N_If_Statement =>
+                  Extend_Statement_Sequence (N, Condition (N), 'I');
                   Set_Statement_Entry;
                   Process_Decisions (Condition (N), 'I');
                   Traverse_Declarations_Or_Statements (Then_Statements (N));
@@ -935,78 +982,182 @@ package body Par_SCO is
 
                   Traverse_Declarations_Or_Statements (Else_Statements (N));
 
-                  --  Unconditional exit points
+               --  Case statement, which breaks the current statement sequence,
+               --  but we include the expression in the current sequence.
+
+               when N_Case_Statement =>
+                  Extend_Statement_Sequence (N, Expression (N), 'C');
+                  Set_Statement_Entry;
+                  Process_Decisions (Expression (N), 'X');
+
+                  --  Process case branches
+
+                  declare
+                     Alt : Node_Id;
+
+                  begin
+                     Alt := First (Alternatives (N));
+                     while Present (Alt) loop
+                        Traverse_Declarations_Or_Statements (Statements (Alt));
+                        Next (Alt);
+                     end loop;
+                  end;
+
+               --  Unconditional exit points, which are included in the current
+               --  statement sequence, but then terminate it
 
                when N_Requeue_Statement |
                     N_Goto_Statement    |
                     N_Raise_Statement   =>
+                  Extend_Statement_Sequence (N, ' ');
                   Set_Statement_Entry;
-                  Sloc_Range (N, From, To);
-                  Set_Table_Entry ('T', ' ', From, To, False);
 
-               --  Simple return statement
+               --  Simple return statement. which is an exit point, but we
+               --  have to process the return expression for decisions.
 
                when N_Simple_Return_Statement =>
+                  Extend_Statement_Sequence (N, ' ');
                   Set_Statement_Entry;
-
-                  --  Process possible return expression
-
                   Process_Decisions (Expression (N), 'X');
 
-                  --  Return is an exit point
-
-                  Sloc_Range (N, From, To);
-                  Set_Table_Entry ('T', ' ', From, To, False);
-
                --  Extended return statement
 
                when N_Extended_Return_Statement =>
-                  Set_Statement_Entry;
-                  Traverse_Declarations_Or_Statements
-                    (Return_Object_Declarations (N));
+                  declare
+                     Odecl : constant Node_Id :=
+                               First (Return_Object_Declarations (N));
+                  begin
+                     if Present (Expression (Odecl)) then
+                        Extend_Statement_Sequence
+                          (N, Expression (Odecl), 'R');
+                        Process_Decisions (Expression (Odecl), 'X');
+                     end if;
+                  end;
+
                   Traverse_Handled_Statement_Sequence
                     (Handled_Statement_Sequence (N));
 
-                  --  Return is an exit point
+               --  Loop ends the current statement sequence, but we include
+               --  the iteration scheme if present in the current sequence.
+               --  But the body of the loop starts a new sequence, since it
+               --  may not be executed as part of the current sequence.
+
+               when N_Loop_Statement =>
+                  if Present (Iteration_Scheme (N)) then
 
-                  Sloc_Range (N, From, To);
-                  Set_Table_Entry ('T', ' ', From, To, False);
+                     --  If iteration scheme present, extend the current
+                     --  statement sequence to include the iteration scheme
+                     --  and process any decisions it contains.
 
-               --  Loop
+                     declare
+                        ISC : constant Node_Id := Iteration_Scheme (N);
 
-               when N_Loop_Statement =>
+                     begin
+                        --  While statement
 
-                  --  Even if not a while loop, we want a new statement seq
+                        if Present (Condition (ISC)) then
+                           Extend_Statement_Sequence (N, ISC, 'W');
+                           Process_Decisions (Condition (ISC), 'W');
 
-                  Set_Statement_Entry;
+                        --  For statement
 
-                  if Present (Iteration_Scheme (N)) then
-                     Process_Decisions
-                       (Condition (Iteration_Scheme (N)), 'W');
+                        else
+                           Extend_Statement_Sequence (N, ISC, 'F');
+                           Process_Decisions
+                             (Loop_Parameter_Specification (ISC), 'X');
+                        end if;
+                     end;
                   end if;
 
+                  Set_Statement_Entry;
                   Traverse_Declarations_Or_Statements (Statements (N));
 
-               --  All other cases
+               --  Pragma
+
+               when N_Pragma =>
+                  Extend_Statement_Sequence (N, 'P');
+
+                  --  For pragmas Assert, Check, Precondition, and
+                  --  Postcondition, we generate decision entries for the
+                  --  condition only if the pragma is enabled. For now, we just
+                  --  check Assertions_Enabled, which will be set to reflect
+                  --  the presence of -gnata.
+
+                  --  Later we should move processing of the relevant pragmas
+                  --  to Par_Prag, and properly set the flag Pragma_Enabled at
+                  --  parse time, so that we can check this flag instead ???
+
+                  --  For all other pragmas, we always generate decision
+                  --  entries for any embedded expressions.
+
+                  declare
+                     Nam : constant Name_Id :=
+                             Chars (Pragma_Identifier (N));
+                     Arg : Node_Id := First (Pragma_Argument_Associations (N));
+                  begin
+                     case Nam is
+                        when Name_Assert        |
+                             Name_Check         |
+                             Name_Precondition  |
+                             Name_Postcondition =>
+
+                           if Nam = Name_Check then
+                              Next (Arg);
+                           end if;
+
+                           if Assertions_Enabled then
+                              Process_Decisions (Expression (Arg), 'P');
+                           end if;
+
+                        when others =>
+                           Process_Decisions (N, 'X');
+                     end case;
+                  end;
+
+               --  All other cases, which extend the current statement sequence
+               --  but do not terminate it, even if they have nested decisions.
 
                when others =>
+
+                  --  Determine required type character code
+
+                  declare
+                     Typ : Character;
+
+                  begin
+                     case Nkind (N) is
+                        when N_Full_Type_Declaration         |
+                             N_Incomplete_Type_Declaration   |
+                             N_Private_Type_Declaration      |
+                             N_Private_Extension_Declaration =>
+                           Typ := 't';
+
+                        when N_Subtype_Declaration           =>
+                           Typ := 's';
+
+                        when N_Object_Declaration            =>
+                           Typ := 'o';
+
+                        when N_Renaming_Declaration          =>
+                           Typ := 'r';
+
+                        when N_Generic_Instantiation         =>
+                           Typ := 'i';
+
+                        when others                          =>
+                           Typ := ' ';
+                     end case;
+
+                     Extend_Statement_Sequence (N, Typ);
+                  end;
+
+                  --  Process any embedded decisions
+
                   if Has_Decision (N) then
-                     Set_Statement_Entry;
                      Process_Decisions (N, 'X');
                   end if;
             end case;
 
-            --  If that element did not terminate the current sequence of
-            --  statements, then establish or extend this sequence.
-
-            if not Term then
-               if Start = No_Location then
-                  Sloc_Range (N, Start, Stop);
-               else
-                  Sloc_Range (N, Dummy, Stop);
-               end if;
-            end if;
-
             Next (N);
          end loop;
 
@@ -1032,7 +1183,12 @@ package body Par_SCO is
       Handler : Node_Id;
 
    begin
-      if Present (N) then
+
+      --  For package bodies without a statement part, the parser adds an empty
+      --  one, to normalize the representation. The null statement therein,
+      --  which does not come from source, does not get a SCO.
+
+      if Present (N) and then Comes_From_Source (N) then
          Traverse_Declarations_Or_Statements (Statements (N));
 
          if Present (Exception_Handlers (N)) then