OSDN Git Service

2011-08-03 Robert Dewar <dewar@adacore.com>
[pf3gnuchains/gcc-fork.git] / gcc / ada / exp_ch5.adb
index bdd5d3a..51ae183 100644 (file)
@@ -6,7 +6,7 @@
 --                                                                          --
 --                                 B o d y                                  --
 --                                                                          --
---          Copyright (C) 1992-2010, Free Software Foundation, Inc.         --
+--          Copyright (C) 1992-2011, Free Software Foundation, Inc.         --
 --                                                                          --
 -- GNAT is free software;  you can  redistribute it  and/or modify it under --
 -- terms of the  GNU General Public License as published  by the Free Soft- --
@@ -1934,22 +1934,21 @@ package body Exp_Ch5 is
 
                --  If the type is tagged, we may as well use the predefined
                --  primitive assignment. This avoids inlining a lot of code
-               --  and in the class-wide case, the assignment is replaced by
-               --  dispatch call to _assign. Note that this cannot be done when
-               --  discriminant checks are locally suppressed (as in extension
-               --  aggregate expansions) because otherwise the discriminant
-               --  check will be performed within the _assign call. It is also
-               --  suppressed for assignments created by the expander that
-               --  correspond to initializations, where we do want to copy the
-               --  tag (No_Ctrl_Actions flag set True) by the expander and we
-               --  do not need to mess with tags ever (Expand_Ctrl_Actions flag
-               --  is set True in this case).
+               --  and in the class-wide case, the assignment is replaced
+               --  by a dispatching call to _assign. It is suppressed in the
+               --  case of assignments created by the expander that correspond
+               --  to initializations, where we do want to copy the tag
+               --  (Expand_Ctrl_Actions flag is set True in this case). It is
+               --  also suppressed if restriction No_Dispatching_Calls is in
+               --  force because in that case predefined primitives are not
+               --  generated.
 
                or else (Is_Tagged_Type (Typ)
                          and then not Is_Value_Type (Etype (Lhs))
                          and then Chars (Current_Scope) /= Name_uAssign
                          and then Expand_Ctrl_Actions
-                         and then not Discriminant_Checks_Suppressed (Empty))
+                         and then
+                           not Restriction_Active (No_Dispatching_Calls))
             then
                --  Fetch the primitive op _assign and proper type to call it.
                --  Because of possible conflicts between private and full view,
@@ -2762,109 +2761,110 @@ package body Exp_Ch5 is
    --------------------------
 
    procedure Expand_Iterator_Loop (N : Node_Id) is
-      Loc        : constant Source_Ptr := Sloc (N);
-      Isc        : constant Node_Id    := Iteration_Scheme (N);
-      I_Spec     : constant Node_Id    := Iterator_Specification (Isc);
-      Id         : constant Entity_Id  := Defining_Identifier (I_Spec);
-      Container  : constant Entity_Id  :=  Entity (Name (I_Spec));
-      Typ        : constant Entity_Id  := Etype (Container);
+      Isc    : constant Node_Id    := Iteration_Scheme (N);
+      I_Spec : constant Node_Id    := Iterator_Specification (Isc);
+      Id     : constant Entity_Id  := Defining_Identifier (I_Spec);
+      Loc    : constant Source_Ptr := Sloc (N);
 
-      Cursor   : Entity_Id;
-      New_Loop : Node_Id;
-      Stats    : List_Id;
+      Container     : constant Node_Id   := Name (I_Spec);
+      Container_Typ : constant Entity_Id := Etype (Container);
+      Cursor        : Entity_Id;
+      New_Loop      : Node_Id;
+      Stats         : List_Id := Statements (N);
 
    begin
-      if Is_Array_Type (Typ) then
+      --  Processing for arrays
+
+      if Is_Array_Type (Container_Typ) then
+
+         --  for Element of Array loop
+         --
+         --  This case requires an internally generated cursor to iterate over
+         --  the array.
+
          if Of_Present (I_Spec) then
             Cursor := Make_Temporary (Loc, 'C');
 
-            --  for Elem of Arr loop ...
+            --  Generate:
+            --    Element : Component_Type renames Container (Cursor);
 
-            declare
-               Decl : constant Node_Id :=
-                        Make_Object_Renaming_Declaration (Loc,
-                          Defining_Identifier => Id,
-                          Subtype_Mark        =>
-                            New_Occurrence_Of (Component_Type (Typ), Loc),
-                          Name                =>
-                            Make_Indexed_Component (Loc,
-                              Prefix      =>
-                                New_Occurrence_Of (Container, Loc),
-                              Expressions =>
-                                New_List (New_Occurrence_Of (Cursor, Loc))));
-            begin
-               Stats := Statements (N);
-               Prepend (Decl, Stats);
+            Prepend_To (Stats,
+              Make_Object_Renaming_Declaration (Loc,
+                Defining_Identifier => Id,
+                Subtype_Mark =>
+                  New_Reference_To (Component_Type (Container_Typ), Loc),
+                Name =>
+                  Make_Indexed_Component (Loc,
+                    Prefix => Relocate_Node (Container),
+                    Expressions => New_List (
+                      New_Reference_To (Cursor, Loc)))));
 
-               New_Loop :=
-                 Make_Loop_Statement (Loc,
-                   Iteration_Scheme =>
-                     Make_Iteration_Scheme (Loc,
-                       Loop_Parameter_Specification =>
-                         Make_Loop_Parameter_Specification (Loc,
-                           Defining_Identifier         => Cursor,
-                           Discrete_Subtype_Definition =>
-                              Make_Attribute_Reference (Loc,
-                                Prefix         =>
-                                  New_Occurrence_Of (Container, Loc),
-                                Attribute_Name => Name_Range),
-                           Reverse_Present => Reverse_Present (I_Spec))),
-                   Statements       => Stats,
-                   End_Label        => Empty);
-            end;
+         --  for Index in Array loop
+         --
+         --  This case utilizes the already given cursor name
 
          else
-            --  for Index in Array loop ...
-
-            --  The cursor (index into the array) is the source Id
-
             Cursor := Id;
-            New_Loop :=
-              Make_Loop_Statement (Loc,
-                Iteration_Scheme =>
-                  Make_Iteration_Scheme (Loc,
-                    Loop_Parameter_Specification =>
-                      Make_Loop_Parameter_Specification (Loc,
-                        Defining_Identifier         => Cursor,
-                        Discrete_Subtype_Definition =>
-                           Make_Attribute_Reference (Loc,
-                             Prefix         =>
-                               New_Occurrence_Of (Container, Loc),
-                             Attribute_Name => Name_Range),
-                        Reverse_Present => Reverse_Present (I_Spec))),
-                Statements       => Statements (N),
-                End_Label        => Empty);
          end if;
 
-      --  Iterators over containers
+         --  Generate:
+         --    for Cursor in [reverse] Container'Range loop
+         --       Element : Component_Type renames Container (Cursor);
+         --       --  for the "of" form
+         --
+         --       <original loop statements>
+         --    end loop;
+
+         New_Loop :=
+           Make_Loop_Statement (Loc,
+             Iteration_Scheme =>
+               Make_Iteration_Scheme (Loc,
+                 Loop_Parameter_Specification =>
+                   Make_Loop_Parameter_Specification (Loc,
+                     Defining_Identifier => Cursor,
+                       Discrete_Subtype_Definition =>
+                         Make_Attribute_Reference (Loc,
+                           Prefix => Relocate_Node (Container),
+                           Attribute_Name => Name_Range),
+                      Reverse_Present => Reverse_Present (I_Spec))),
+              Statements => Stats,
+              End_Label  => Empty);
+
+      --  Processing for containers
 
       else
-         --  In both cases these require a cursor of the proper type
+         --  The for loop is expanded into a while loop which uses a container
+         --  specific cursor to examine each element.
 
-         --    Cursor : P.Cursor_Type := Container.First;
-         --    while Cursor /= P.No_Element loop
+         --    Cursor : Pack.Cursor := Container.First;
+         --    while Cursor /= Pack.No_Element loop
+         --       declare
+         --       --  the block is added when Element_Type is controlled
 
-         --       Obj : P.Element_Type renames Element (Cursor);
-         --       --  For the "of" form, the element name renames the element
-         --       --  designated by the cursor.
+         --          Obj : Pack.Element_Type := Element (Cursor);
+         --          --  for the "of" loop form
+         --       begin
+         --          <original loop statements>
+         --       end;
 
-         --       Statements;
-         --       P.Next (Cursor);
+         --       Pack.Next (Cursor);
          --    end loop;
 
-         --  with the obvious replacements if "reverse" is specified.
+         --  If "reverse" is present, then the initialization of the cursor
+         --  uses Last and the step becomes Prev. Pack is the name of the
+         --  package which instantiates the container.
 
          declare
-            Element_Type  : constant Entity_Id := Etype (Id);
-            Pack          : constant Entity_Id := Scope (Etype (Container));
-            Name_Init     : Name_Id;
-            Name_Step     : Name_Id;
-            Cond          : Node_Id;
-            Cursor_Decl   : Node_Id;
-            Renaming_Decl : Node_Id;
+            Element_Type : constant Entity_Id := Etype (Id);
+            Pack         : constant Entity_Id :=
+                             Scope (Base_Type (Container_Typ));
+            Decl         : Node_Id;
+            Cntr         : Node_Id;
+            Name_Init    : Name_Id;
+            Name_Step    : Name_Id;
 
          begin
-            Stats := Statements (N);
+            --  The "of" case uses an internally generated cursor
 
             if Of_Present (I_Spec) then
                Cursor := Make_Temporary (Loc, 'C');
@@ -2872,88 +2872,167 @@ package body Exp_Ch5 is
                Cursor := Id;
             end if;
 
-            if Reverse_Present (I_Spec) then
+            --  The code below only handles containers where Element is not a
+            --  primitive operation of the container. This excludes for now the
+            --  Hi-Lite formal containers.
+
+            if Of_Present (I_Spec) then
+
+               --  Generate:
+               --    Id : Element_Type := Pack.Element (Cursor);
+
+               Decl :=
+                 Make_Object_Renaming_Declaration (Loc,
+                   Defining_Identifier => Id,
+                   Subtype_Mark =>
+                     New_Reference_To (Element_Type, Loc),
+                   Name =>
+                     Make_Indexed_Component (Loc,
+                       Prefix =>
+                         Make_Selected_Component (Loc,
+                           Prefix =>
+                             New_Reference_To (Pack, Loc),
+                           Selector_Name =>
+                             Make_Identifier (Loc, Chars => Name_Element)),
+                       Expressions => New_List (
+                         New_Reference_To (Cursor, Loc))));
+
+               --  When the container holds controlled objects, wrap the loop
+               --  statements and element renaming declaration with a block.
+               --  This ensures that the transient result of Element (Cursor)
+               --  is cleaned up after each iteration of the loop.
+
+               if Needs_Finalization (Element_Type) then
+
+                  --  Generate:
+                  --    declare
+                  --       Id : Element_Type := Pack.Element (Cursor);
+                  --    begin
+                  --       <original loop statments>
+                  --    end;
+
+                  Stats := New_List (
+                    Make_Block_Statement (Loc,
+                      Declarations => New_List (Decl),
+                      Handled_Statement_Sequence =>
+                        Make_Handled_Sequence_Of_Statements (Loc,
+                          Statements => Stats)));
+               else
+                  Prepend_To (Stats, Decl);
+               end if;
+            end if;
 
-               --  Must verify that the container has a reverse iterator ???
+            --  Determine the advancement and initialization steps for the
+            --  cursor.
 
+            --  Must verify that the container has a reverse iterator ???
+
+            if Reverse_Present (I_Spec) then
                Name_Init := Name_Last;
                Name_Step := Name_Previous;
-
             else
                Name_Init := Name_First;
                Name_Step := Name_Next;
             end if;
 
-            --  C : Cursor_Type := Container.First;
+            --  For both iterator forms, add a call to the step operation to
+            --  advance the cursor. Generate:
+            --
+            --    Pack.[Next | Prev] (Cursor);
 
-            Cursor_Decl :=
-              Make_Object_Declaration (Loc,
-                Defining_Identifier => Cursor,
-                Object_Definition   =>
-                  Make_Selected_Component (Loc,
-                    Prefix        => New_Occurrence_Of (Pack, Loc),
-                    Selector_Name => Make_Identifier (Loc, Name_Cursor)),
-                Expression =>
+            Append_To (Stats,
+              Make_Procedure_Call_Statement (Loc,
+                Name =>
                   Make_Selected_Component (Loc,
-                    Prefix        => New_Occurrence_Of (Container, Loc),
-                    Selector_Name => Make_Identifier (Loc, Name_Init)));
+                    Prefix =>
+                      New_Reference_To (Pack, Loc),
+                    Selector_Name =>
+                      Make_Identifier (Loc, Name_Step)),
 
-            Insert_Action (N, Cursor_Decl);
+                Parameter_Associations => New_List (
+                  New_Reference_To (Cursor, Loc))));
 
-            --  while C /= No_Element loop
+            --  Generate:
+            --    while Cursor /= Pack.No_Element loop
+            --       <Stats>
+            --    end loop;
 
-            Cond := Make_Op_Ne (Loc,
-                      Left_Opnd  => New_Occurrence_Of (Cursor, Loc),
-                      Right_Opnd => Make_Selected_Component (Loc,
-                         Prefix        => New_Occurrence_Of (Pack, Loc),
-                         Selector_Name =>
-                           Make_Identifier (Loc, Name_No_Element)));
+            New_Loop :=
+              Make_Loop_Statement (Loc,
+                Iteration_Scheme =>
+                  Make_Iteration_Scheme (Loc,
+                    Condition =>
+                      Make_Op_Ne (Loc,
+                        Left_Opnd =>
+                          New_Reference_To (Cursor, Loc),
+                        Right_Opnd =>
+                          Make_Selected_Component (Loc,
+                            Prefix =>
+                              New_Reference_To (Pack, Loc),
+                            Selector_Name =>
+                              Make_Identifier (Loc, Name_No_Element)))),
+                Statements => Stats,
+                End_Label  => Empty);
+
+            Cntr := Relocate_Node (Container);
+
+            --  When the container is provided by a function call, create an
+            --  explicit renaming of the function result. Generate:
+            --
+            --    Cnn : Container_Typ renames Func_Call (...);
+            --
+            --  The renaming avoids the generation of a transient scope when
+            --  initializing the cursor and the premature finalization of the
+            --  container.
+
+            if Nkind (Cntr) = N_Function_Call then
+               declare
+                  Ren_Id : constant Entity_Id := Make_Temporary (Loc, 'C');
 
-            if Of_Present (I_Spec) then
+               begin
+                  Insert_Action (N,
+                    Make_Object_Renaming_Declaration (Loc,
+                      Defining_Identifier => Ren_Id,
+                      Subtype_Mark =>
+                        New_Reference_To (Container_Typ, Loc),
+                      Name => Cntr));
+
+                  Cntr := New_Reference_To (Ren_Id, Loc);
+               end;
+            end if;
 
-               --  Id : Element_Type renames Pack.Element (Cursor);
+            --  Create the declaration of the cursor and insert it before the
+            --  source loop. Generate:
+            --
+            --    C : Pack.Cursor_Type := Container.[First | Last];
 
-               Renaming_Decl :=
-                 Make_Object_Renaming_Declaration (Loc,
-                   Defining_Identifier => Id,
-                   Subtype_Mark        =>
-                     New_Occurrence_Of (Element_Type, Loc),
-                   Name                =>
-                     Make_Indexed_Component (Loc,
-                       Prefix =>
-                         Make_Selected_Component (Loc,
-                           Prefix        =>  New_Occurrence_Of (Pack, Loc),
-                           Selector_Name =>
-                             Make_Identifier (Loc, Chars => Name_Element)),
-                       Expressions =>
-                         New_List (New_Occurrence_Of (Cursor, Loc))));
+            Insert_Action (N,
+              Make_Object_Declaration (Loc,
+                Defining_Identifier => Cursor,
+                Object_Definition =>
+                  Make_Selected_Component (Loc,
+                    Prefix =>
+                      New_Reference_To (Pack, Loc),
+                    Selector_Name =>
+                      Make_Identifier (Loc, Name_Cursor)),
 
-               Prepend (Renaming_Decl, Stats);
-            end if;
+                Expression =>
+                  Make_Selected_Component (Loc,
+                    Prefix => Cntr,
+                    Selector_Name =>
+                      Make_Identifier (Loc, Name_Init))));
 
-            --  For both iterator forms, add call to step operation (Next or
-            --  Previous) to advance cursor.
+            --  If the range of iteration is given by a function call that
+            --  returns a container, the finalization actions have been saved
+            --  in the Condition_Actions of the iterator. Insert them now at
+            --  the head of the loop.
 
-            Append_To (Stats,
-              Make_Procedure_Call_Statement (Loc,
-                Name =>
-                  Make_Selected_Component (Loc,
-                    Prefix        => New_Occurrence_Of (Pack, Loc),
-                    Selector_Name => Make_Identifier (Loc, Name_Step)),
-                Parameter_Associations =>
-                  New_List (New_Occurrence_Of (Cursor, Loc))));
-
-            New_Loop := Make_Loop_Statement (Loc,
-              Iteration_Scheme =>
-                Make_Iteration_Scheme (Loc, Condition => Cond),
-              Statements       => Stats,
-              End_Label        => Empty);
+            if Present (Condition_Actions (Isc)) then
+               Insert_List_Before (N, Condition_Actions (Isc));
+            end if;
          end;
       end if;
 
-      --  Set_Analyzed (I_Spec);
-      --  Why is this commented out???
-
       Rewrite (N, New_Loop);
       Analyze (N);
    end Expand_Iterator_Loop;
@@ -3157,6 +3236,7 @@ package body Exp_Ch5 is
 
       elsif Present (Isc)
         and then Present (Condition_Actions (Isc))
+        and then Present (Condition (Isc))
       then
          declare
             ES : Node_Id;