OSDN Git Service

Fix typo in previous patch.
[pf3gnuchains/gcc-fork.git] / gcc / ada / sem.adb
index d3a7c35..bac147c 100644 (file)
@@ -243,7 +243,7 @@ package body Sem is
             Analyze_Free_Statement (N);
 
          when N_Freeze_Entity =>
-            null;  -- no semantic processing required
+            Analyze_Freeze_Entity (N);
 
          when N_Full_Type_Declaration =>
             Analyze_Type_Declaration (N);
@@ -603,6 +603,18 @@ package body Sem is
          when N_Push_Pop_xxx_Label =>
             null;
 
+         --  SCIL nodes don't need analysis because they are decorated when
+         --  they are built. They are added to the tree by Insert_Actions and
+         --  the call to analyze them is generated when the full list is
+         --  analyzed.
+
+         when
+           N_SCIL_Dispatch_Table_Object_Init        |
+           N_SCIL_Dispatch_Table_Tag_Init           |
+           N_SCIL_Dispatching_Call                  |
+           N_SCIL_Tag_Init                          =>
+            null;
+
          --  For the remaining node types, we generate compiler abort, because
          --  these nodes are always analyzed within the Sem_Chn routines and
          --  there should never be a case of making a call to the main Analyze
@@ -1510,13 +1522,19 @@ package body Sem is
       --  after we have fully processed X, and is used only for debugging
       --  printouts and assertions.
 
+      Do_Main : Boolean := False;
+      --  Flag to delay processing the main body until after all other units.
+      --  This is needed because the spec of the main unit may appear in the
+      --  context of some other unit. We do not want this to force processing
+      --  of the main body before all other units have been processed.
+
       procedure Do_Action (CU : Node_Id; Item : Node_Id);
       --  Calls Action, with some validity checks
 
       procedure Do_Unit_And_Dependents (CU : Node_Id; Item : Node_Id);
-      --  Calls Do_Action, first on the units with'ed by this one, then on this
-      --  unit. If it's an instance body, do the spec first. If it's an
-      --  instance spec, do the body last.
+      --  Calls Do_Action, first on the units with'ed by this one, then on
+      --  this unit. If it's an instance body, do the spec first. If it is
+      --  an instance spec, do the body last.
 
       ---------------
       -- Do_Action --
@@ -1530,29 +1548,40 @@ package body Sem is
          pragma Assert (No (CU) or else Nkind (CU) = N_Compilation_Unit);
 
          case Nkind (Item) is
-            when N_Generic_Subprogram_Declaration     |
-              N_Generic_Package_Declaration           |
-              N_Package_Declaration                   |
-              N_Subprogram_Declaration                |
-              N_Subprogram_Renaming_Declaration       |
-              N_Package_Renaming_Declaration          |
-              N_Generic_Function_Renaming_Declaration |
-              N_Generic_Package_Renaming_Declaration  |
-              N_Generic_Procedure_Renaming_Declaration =>
-               null;  --  Specs are OK
-
-            when N_Package_Body | N_Subprogram_Body =>
-               --  A body must be the main unit
+            when N_Generic_Subprogram_Declaration        |
+                 N_Generic_Package_Declaration           |
+                 N_Package_Declaration                   |
+                 N_Subprogram_Declaration                |
+                 N_Subprogram_Renaming_Declaration       |
+                 N_Package_Renaming_Declaration          |
+                 N_Generic_Function_Renaming_Declaration |
+                 N_Generic_Package_Renaming_Declaration  |
+                 N_Generic_Procedure_Renaming_Declaration =>
+
+               --  Specs are OK
+
+               null;
+
+            when N_Package_Body  =>
+
+               --  Package bodies are processed immediately after the
+               --  corresponding spec.
+
+               null;
+
+            when  N_Subprogram_Body =>
+
+               --  A subprogram body must be the main unit
 
                pragma Assert (Acts_As_Spec (CU)
-                              or else CU = Cunit (Main_Unit));
+                               or else CU = Cunit (Main_Unit));
                null;
 
             --  All other cases cannot happen
 
-            when N_Function_Instantiation |
-              N_Procedure_Instantiation   |
-              N_Package_Instantiation     =>
+            when N_Function_Instantiation  |
+                 N_Procedure_Instantiation |
+                 N_Package_Instantiation   =>
                pragma Assert (False, "instantiation");
                null;
 
@@ -1570,8 +1599,8 @@ package body Sem is
             pragma Assert (Item = Unit (CU));
 
             declare
-               Unit_Num     : constant Unit_Number_Type :=
-                                Get_Cunit_Unit_Number (CU);
+               Unit_Num : constant Unit_Number_Type :=
+                            Get_Cunit_Unit_Number (CU);
 
                procedure Assert_Done (Withed_Unit : Node_Id);
                --  Assert Withed_Unit is already Done, unless it's a body. It
@@ -1581,21 +1610,27 @@ package body Sem is
                --  spec is also created). With clauses pointing to the
                --  instantiation end up pointing to the instance body.
 
+               -----------------
+               -- Assert_Done --
+               -----------------
+
                procedure Assert_Done (Withed_Unit : Node_Id) is
                begin
                   if not Done (Get_Cunit_Unit_Number (Withed_Unit)) then
                      if not Nkind_In
-                       (Unit (Withed_Unit), N_Package_Body, N_Subprogram_Body)
+                              (Unit (Withed_Unit),
+                                 N_Generic_Package_Declaration,
+                                 N_Package_Body,
+                                 N_Subprogram_Body)
                      then
-
                         Write_Unit_Name
-                          (Unit_Name
-                           (Get_Cunit_Unit_Number
-                            (Withed_Unit)));
+                          (Unit_Name (Get_Cunit_Unit_Number (Withed_Unit)));
                         Write_Str (" not yet walked!");
+
                         if Get_Cunit_Unit_Number (Withed_Unit) = Unit_Num then
                            Write_Str (" (self-ref)");
                         end if;
+
                         Write_Eol;
 
                         pragma Assert (False);
@@ -1604,15 +1639,19 @@ package body Sem is
                end Assert_Done;
 
                procedure Assert_Withed_Units_Done is
-                  new Walk_Withs (Assert_Done);
+                 new Walk_Withs (Assert_Done);
+
             begin
                if Debug_Unit_Walk then
-                  Write_Unit_Info (Unit_Num, Item);
+                  Write_Unit_Info (Unit_Num, Item, Withs => True);
                end if;
 
-               --  Main unit should come last
+               --  Main unit should come last (except in the case where we
+               --  skipped System_Aux_Id, in which case we missed the things it
+               --  depends on).
 
-               pragma Assert (not Done (Main_Unit));
+               pragma Assert
+                 (not Done (Main_Unit) or else Present (System_Aux_Id));
 
                --  We shouldn't do the same thing twice
 
@@ -1648,74 +1687,131 @@ package body Sem is
          procedure Do_Withed_Unit (Withed_Unit : Node_Id);
          --  Pass the buck to Do_Unit_And_Dependents
 
+         --------------------
+         -- Do_Withed_Unit --
+         --------------------
+
          procedure Do_Withed_Unit (Withed_Unit : Node_Id) is
+            Save_Do_Main : constant Boolean := Do_Main;
+
          begin
+            --  Do not process the main unit if coming from a with_clause,
+            --  as would happen with a parent body that has a child spec
+            --  in its context.
+
+            Do_Main := False;
             Do_Unit_And_Dependents (Withed_Unit, Unit (Withed_Unit));
+            Do_Main := Save_Do_Main;
          end Do_Withed_Unit;
 
          procedure Do_Withed_Units is new Walk_Withs (Do_Withed_Unit);
+
+      --  Start of processing for Do_Unit_And_Dependents
+
       begin
-         if Seen (Unit_Num) then
-            return;
-         end if;
+         if not Seen (Unit_Num) then
 
-         Seen (Unit_Num) := True;
+            --  Process the with clauses
 
-         --  Process corresponding spec of body first
+            Do_Withed_Units (CU, Include_Limited => False);
 
-         if Nkind_In (Item, N_Package_Body, N_Subprogram_Body) then
-            declare
-               Spec_Unit : constant Node_Id := Library_Unit (CU);
-            begin
-               if Spec_Unit = CU then  --  ???Why needed?
-                  pragma Assert (Acts_As_Spec (CU));
-                  null;
+            --  Process the unit if it is a spec. If it is the main unit,
+            --  process it only if we have done all other units.
+
+            if not Nkind_In (Item, N_Package_Body, N_Subprogram_Body)
+              or else Acts_As_Spec (CU)
+            then
+               if CU = Cunit (Main_Unit) and then not Do_Main then
+                  Seen (Unit_Num) := False;
 
                else
-                  Do_Unit_And_Dependents (Spec_Unit, Unit (Spec_Unit));
+                  Seen (Unit_Num) := True;
+                  Do_Action (CU, Item);
+                  Done (Unit_Num) := True;
                end if;
-            end;
+            end if;
          end if;
 
-         --  Process the with clauses
+         --  Process bodies. The spec, if present, has been processed already.
+         --  A body appears if it is the main, or the body of a spec that is
+         --  in the context of the main unit, and that is instantiated, or else
+         --  contains a generic that is instantiated, or a subprogram that is
+         --  or a subprogram that is inlined in the main unit.
 
-         Do_Withed_Units (CU, Include_Limited => False);
+         --  We exclude bodies that may appear in a circular dependency list,
+         --  where spec A depends on spec B and body of B depends on spec A.
+         --  This is not an elaboration issue, but body B must be excluded
+         --  from the processing.
 
-         --  Process the unit itself
-
-         if not Nkind_In (Item, N_Package_Body, N_Subprogram_Body)
-           or else Acts_As_Spec (CU)
-           or else CU = Cunit (Main_Unit)
-         then
+         declare
+            Body_Unit :  Node_Id := Empty;
+            Body_Num  : Unit_Number_Type;
 
-            Do_Action (CU, Item);
+            function Circular_Dependence (B : Node_Id) return Boolean;
+            --  Check whether this body depends on a spec that is pending,
+            --  that is to say has been seen but not processed yet.
 
-            Done (Unit_Num) := True;
-         end if;
+            -------------------------
+            -- Circular_Dependence --
+            -------------------------
 
-         --  Process corresponding body of spec last. However, if this body is
-         --  the main unit (because some dependent of the main unit depends on
-         --  the main unit's spec), we don't process it now. We also skip
-         --  processing of the body of a unit named by pragma Extend_System,
-         --  because it has cyclic dependences in some cases.
+            function Circular_Dependence (B : Node_Id) return Boolean is
+               Item : Node_Id;
+               UN   : Unit_Number_Type;
 
-         if not Nkind_In (Item, N_Package_Body, N_Subprogram_Body) then
-            declare
-               Body_Unit : constant Node_Id := Library_Unit (CU);
             begin
-               if Present (Body_Unit)
-                 and then Body_Unit /= Cunit (Main_Unit)
-                 and then Unit_Num /= Get_Source_Unit (System_Aux_Id)
-               then
-                  Do_Unit_And_Dependents (Body_Unit, Unit (Body_Unit));
-               end if;
-            end;
-         end if;
+               Item := First (Context_Items (B));
+               while Present (Item) loop
+                  if Nkind (Item) = N_With_Clause then
+                     UN := Get_Cunit_Unit_Number (Library_Unit (Item));
+
+                     if Seen (UN)
+                       and then not Done (UN)
+                     then
+                        return True;
+                     end if;
+                  end if;
+
+                  Next (Item);
+               end loop;
+
+               return False;
+            end Circular_Dependence;
+
+         begin
+            if Nkind (Item) = N_Package_Declaration then
+               Body_Unit := Library_Unit (CU);
+
+            elsif Nkind_In (Item, N_Package_Body, N_Subprogram_Body) then
+               Body_Unit := CU;
+            end if;
+
+            if Present (Body_Unit)
+
+              --  Since specs and bodies are not done at the same time,
+              --  guard against listing a body more than once. Bodies are
+              --  only processed when the main unit is being processed,
+              --  after all other units in the list. The DEC extension
+              --  to System is excluded because of circularities.
+
+              and then not Seen (Get_Cunit_Unit_Number (Body_Unit))
+              and then
+                (No (System_Aux_Id)
+                   or else Unit_Num /= Get_Source_Unit (System_Aux_Id))
+              and then not Circular_Dependence (Body_Unit)
+              and then Do_Main
+            then
+               Body_Num := Get_Cunit_Unit_Number (Body_Unit);
+               Seen (Body_Num) := True;
+               Do_Action (Body_Unit, Unit (Body_Unit));
+               Done (Body_Num) := True;
+            end if;
+         end;
       end Do_Unit_And_Dependents;
 
       --  Local Declarations
 
-      Cur : Elmt_Id := First_Elmt (Comp_Unit_List);
+      Cur : Elmt_Id;
 
    --  Start of processing for Walk_Library_Items
 
@@ -1729,52 +1825,48 @@ package body Sem is
 
       Do_Action (Empty, Standard_Package_Node);
 
+      --  First place the context of all instance bodies on the corresponding
+      --  spec, because it may be needed to analyze the code at the place of
+      --  the instantiation.
+
+      Cur := First_Elmt (Comp_Unit_List);
       while Present (Cur) loop
          declare
             CU : constant Node_Id := Node (Cur);
             N  : constant Node_Id := Unit (CU);
 
          begin
-            pragma Assert (Nkind (CU) = N_Compilation_Unit);
-
-            case Nkind (N) is
-
-               --  If it's a body, then ignore it, unless it's an instance (in
-               --  which case we do the spec), or it's the main unit (in which
-               --  case we do it). Note that it could be both, in which case we
-               --  do the spec first.
-
-               when N_Package_Body | N_Subprogram_Body =>
-                  declare
-                     Entity : Node_Id := N;
+            if Nkind (N) = N_Package_Body
+              and then Is_Generic_Instance (Defining_Entity (N))
+            then
+               Append_List
+                 (Context_Items (CU), Context_Items (Library_Unit (CU)));
+            end if;
 
-                  begin
-                     if Nkind (Entity) = N_Subprogram_Body then
-                        Entity := Specification (Entity);
-                     end if;
+            Next_Elmt (Cur);
+         end;
+      end loop;
 
-                     Entity := Defining_Unit_Name (Entity);
+      --  Now traverse compilation units in order
 
-                     if Nkind (Entity) not in N_Entity then
+      Cur := First_Elmt (Comp_Unit_List);
+      while Present (Cur) loop
+         declare
+            CU : constant Node_Id := Node (Cur);
+            N  : constant Node_Id := Unit (CU);
 
-                        --  Must be N_Defining_Program_Unit_Name
+         begin
+            pragma Assert (Nkind (CU) = N_Compilation_Unit);
 
-                        Entity := Defining_Identifier (Entity);
-                     end if;
+            case Nkind (N) is
 
-                     if Is_Generic_Instance (Entity) then
-                        declare
-                           Spec_Unit : constant Node_Id := Library_Unit (CU);
-                        begin
-                           Do_Unit_And_Dependents
-                             (Spec_Unit, Unit (Spec_Unit));
-                        end;
-                     end if;
-                  end;
+               --  If it's a body, ignore it. Bodies appear in the list only
+               --  because of inlining/instantiations, and they are processed
+               --  immediately after the corresponding specs. The main unit is
+               --  processed separately after all other units.
 
-                  if CU = Cunit (Main_Unit) then
-                     Do_Unit_And_Dependents (CU, N);
-                  end if;
+               when N_Package_Body | N_Subprogram_Body =>
+                  null;
 
                --  It's a spec, so just do it
 
@@ -1786,6 +1878,29 @@ package body Sem is
          Next_Elmt (Cur);
       end loop;
 
+      if not Done (Main_Unit) then
+         Do_Main := True;
+
+         declare
+            Main_CU : constant Node_Id := Cunit (Main_Unit);
+
+         begin
+            --  If the main unit is an instantiation, the body appears before
+            --  the instance spec, which is added later to the unit list. Do
+            --  the spec if present, body will follow.
+
+            if Nkind (Original_Node (Unit (Main_CU)))
+                 in N_Generic_Instantiation
+              and then Present (Library_Unit (Main_CU))
+            then
+               Do_Unit_And_Dependents
+                 (Library_Unit (Main_CU), Unit (Library_Unit (Main_CU)));
+            else
+               Do_Unit_And_Dependents (Main_CU, Unit (Main_CU));
+            end if;
+         end;
+      end if;
+
       if Debug_Unit_Walk then
          if Done /= (Done'Range => True) then
             Write_Eol;
@@ -1795,7 +1910,8 @@ package body Sem is
 
             for Unit_Num in Done'Range loop
                if not Done (Unit_Num) then
-                  Write_Unit_Info (Unit_Num, Unit (Cunit (Unit_Num)));
+                  Write_Unit_Info
+                    (Unit_Num, Unit (Cunit (Unit_Num)), Withs => True);
                end if;
             end loop;
 
@@ -1820,32 +1936,34 @@ package body Sem is
       pragma Assert (Nkind (Unit (CU)) /= N_Subunit);
 
       procedure Walk_Immediate is new Walk_Withs_Immediate (Action);
+
    begin
       --  First walk the withs immediately on the library item
 
       Walk_Immediate (CU, Include_Limited);
 
-      --  For a body, we must also check for any subunits which belong to
-      --  it and which have context clauses of their own, since these
-      --  with'ed units are part of its own dependencies.
+      --  For a body, we must also check for any subunits which belong to it
+      --  and which have context clauses of their own, since these with'ed
+      --  units are part of its own dependencies.
 
       if Nkind (Unit (CU)) in N_Unit_Body then
          for S in Main_Unit .. Last_Unit loop
 
-            --  We are only interested in subunits.  For preproc. data and
-            --  def. files, Cunit is Empty, so we need to test that first.
+            --  We are only interested in subunits. For preproc. data and def.
+            --  files, Cunit is Empty, so we need to test that first.
 
             if Cunit (S) /= Empty
               and then Nkind (Unit (Cunit (S))) = N_Subunit
             then
                declare
                   Pnode : Node_Id;
+
                begin
                   Pnode := Library_Unit (Cunit (S));
 
-                  --  In -gnatc mode, the errors in the subunits will not
-                  --  have been recorded, but the analysis of the subunit
-                  --  may have failed, so just quit.
+                  --  In -gnatc mode, the errors in the subunits will not have
+                  --  been recorded, but the analysis of the subunit may have
+                  --  failed, so just quit.
 
                   if No (Pnode) then
                      exit;
@@ -1858,9 +1976,11 @@ package body Sem is
                   end loop;
 
                   --  See if it belongs to current unit, and if so, include its
-                  --  with_clauses.
+                  --  with_clauses. Do not process main unit prematurely.
 
-                  if Pnode = CU then
+                  if Pnode = CU
+                    and then CU /= Cunit (Main_Unit)
+                  then
                      Walk_Immediate (Cunit (S), Include_Limited);
                   end if;
                end;
@@ -1876,8 +1996,10 @@ package body Sem is
    procedure Walk_Withs_Immediate (CU : Node_Id; Include_Limited : Boolean) is
       pragma Assert (Nkind (CU) = N_Compilation_Unit);
 
-      Context_Item : Node_Id := First (Context_Items (CU));
+      Context_Item : Node_Id;
+
    begin
+      Context_Item := First (Context_Items (CU));
       while Present (Context_Item) loop
          if Nkind (Context_Item) = N_With_Clause
            and then (Include_Limited
@@ -1926,11 +2048,13 @@ package body Sem is
       end if;
 
       declare
-         Context_Item : Node_Id := First (Context_Items (Cunit (Unit_Num)));
+         Context_Item : Node_Id;
+
       begin
+         Context_Item := First (Context_Items (Cunit (Unit_Num)));
          while Present (Context_Item)
            and then (Nkind (Context_Item) /= N_With_Clause
-                     or else Limited_Present (Context_Item))
+                      or else Limited_Present (Context_Item))
          loop
             Context_Item := Next (Context_Item);
          end loop;
@@ -1947,10 +2071,12 @@ package body Sem is
                   pragma Assert (Present (Library_Unit (Context_Item)));
                   Write_Unit_Name
                     (Unit_Name
-                     (Get_Cunit_Unit_Number (Library_Unit (Context_Item))));
+                       (Get_Cunit_Unit_Number (Library_Unit (Context_Item))));
+
                   if Implicit_With (Context_Item) then
                      Write_Str (" -- implicit");
                   end if;
+
                   Write_Eol;
                end if;