OSDN Git Service

2009-07-20 Bob Duff <duff@adacore.com>
[pf3gnuchains/gcc-fork.git] / gcc / ada / exp_disp.adb
index f60e7bc..165d908 100644 (file)
@@ -80,6 +80,11 @@ package body Exp_Disp is
    --  Returns true if Prim is not a predefined dispatching primitive but it is
    --  an alias of a predefined dispatching primitive (i.e. through a renaming)
 
+   function New_Value (From : Node_Id) return Node_Id;
+   --  From is the original Expression. New_Value is equivalent to a call
+   --  to Duplicate_Subexpr with an explicit dereference when From is an
+   --  access parameter.
+
    function Original_View_In_Visible_Part (Typ : Entity_Id) return Boolean;
    --  Check if the type has a private view or if the public view appears
    --  in the visible part of a package spec.
@@ -95,6 +100,182 @@ package body Exp_Disp is
    --  Ada 2005 (AI-345): Determine the tagged kind of T and return a reference
    --  to an RE_Tagged_Kind enumeration value.
 
+   ----------------------
+   -- Apply_Tag_Checks --
+   ----------------------
+
+   procedure Apply_Tag_Checks (Call_Node : Node_Id) is
+      Loc        : constant Source_Ptr := Sloc (Call_Node);
+      Ctrl_Arg   : constant Node_Id   := Controlling_Argument (Call_Node);
+      Ctrl_Typ   : constant Entity_Id := Base_Type (Etype (Ctrl_Arg));
+      Param_List : constant List_Id   := Parameter_Associations (Call_Node);
+
+      Subp            : Entity_Id;
+      CW_Typ          : Entity_Id;
+      Param           : Node_Id;
+      Typ             : Entity_Id;
+      Eq_Prim_Op      : Entity_Id := Empty;
+
+   begin
+      if No_Run_Time_Mode then
+         Error_Msg_CRT ("tagged types", Call_Node);
+         return;
+      end if;
+
+      --  Apply_Tag_Checks is called directly from the semantics, so we need
+      --  a check to see whether expansion is active before proceeding. In
+      --  addition, there is no need to expand the call when compiling under
+      --  restriction No_Dispatching_Calls; the semantic analyzer has
+      --  previously notified the violation of this restriction.
+
+      if not Expander_Active
+        or else Restriction_Active (No_Dispatching_Calls)
+      then
+         return;
+      end if;
+
+      --  Set subprogram. If this is an inherited operation that was
+      --  overridden, the body that is being called is its alias.
+
+      Subp := Entity (Name (Call_Node));
+
+      if Present (Alias (Subp))
+        and then Is_Inherited_Operation (Subp)
+        and then No (DTC_Entity (Subp))
+      then
+         Subp := Alias (Subp);
+      end if;
+
+      --  Definition of the class-wide type and the tagged type
+
+      --  If the controlling argument is itself a tag rather than a tagged
+      --  object, then use the class-wide type associated with the subprogram's
+      --  controlling type. This case can occur when a call to an inherited
+      --  primitive has an actual that originated from a default parameter
+      --  given by a tag-indeterminate call and when there is no other
+      --  controlling argument providing the tag (AI-239 requires dispatching).
+      --  This capability of dispatching directly by tag is also needed by the
+      --  implementation of AI-260 (for the generic dispatching constructors).
+
+      if Ctrl_Typ = RTE (RE_Tag)
+        or else (RTE_Available (RE_Interface_Tag)
+                  and then Ctrl_Typ = RTE (RE_Interface_Tag))
+      then
+         CW_Typ := Class_Wide_Type (Find_Dispatching_Type (Subp));
+
+      --  Class_Wide_Type is applied to the expressions used to initialize
+      --  CW_Typ, to ensure that CW_Typ always denotes a class-wide type, since
+      --  there are cases where the controlling type is resolved to a specific
+      --  type (such as for designated types of arguments such as CW'Access).
+
+      elsif Is_Access_Type (Ctrl_Typ) then
+         CW_Typ := Class_Wide_Type (Designated_Type (Ctrl_Typ));
+
+      else
+         CW_Typ := Class_Wide_Type (Ctrl_Typ);
+      end if;
+
+      Typ := Root_Type (CW_Typ);
+
+      if Ekind (Typ) = E_Incomplete_Type then
+         Typ := Non_Limited_View (Typ);
+      end if;
+
+      if not Is_Limited_Type (Typ) then
+         Eq_Prim_Op := Find_Prim_Op (Typ, Name_Op_Eq);
+      end if;
+
+      --  Dispatching call to C++ primitive
+
+      if Is_CPP_Class (Typ) then
+         null;
+
+      --  Dispatching call to Ada primitive
+
+      elsif Present (Param_List) then
+
+         --  Generate the Tag checks when appropriate
+
+         Param := First_Actual (Call_Node);
+         while Present (Param) loop
+
+            --  No tag check with itself
+
+            if Param = Ctrl_Arg then
+               null;
+
+            --  No tag check for parameter whose type is neither tagged nor
+            --  access to tagged (for access parameters)
+
+            elsif No (Find_Controlling_Arg (Param)) then
+               null;
+
+            --  No tag check for function dispatching on result if the
+            --  Tag given by the context is this one
+
+            elsif Find_Controlling_Arg (Param) = Ctrl_Arg then
+               null;
+
+            --  "=" is the only dispatching operation allowed to get
+            --  operands with incompatible tags (it just returns false).
+            --  We use Duplicate_Subexpr_Move_Checks instead of calling
+            --  Relocate_Node because the value will be duplicated to
+            --  check the tags.
+
+            elsif Subp = Eq_Prim_Op then
+               null;
+
+            --  No check in presence of suppress flags
+
+            elsif Tag_Checks_Suppressed (Etype (Param))
+              or else (Is_Access_Type (Etype (Param))
+                         and then Tag_Checks_Suppressed
+                                    (Designated_Type (Etype (Param))))
+            then
+               null;
+
+            --  Optimization: no tag checks if the parameters are identical
+
+            elsif Is_Entity_Name (Param)
+              and then Is_Entity_Name (Ctrl_Arg)
+              and then Entity (Param) = Entity (Ctrl_Arg)
+            then
+               null;
+
+            --  Now we need to generate the Tag check
+
+            else
+               --  Generate code for tag equality check
+               --  Perhaps should have Checks.Apply_Tag_Equality_Check???
+
+               Insert_Action (Ctrl_Arg,
+                 Make_Implicit_If_Statement (Call_Node,
+                   Condition =>
+                     Make_Op_Ne (Loc,
+                       Left_Opnd =>
+                         Make_Selected_Component (Loc,
+                           Prefix => New_Value (Ctrl_Arg),
+                           Selector_Name =>
+                             New_Reference_To
+                               (First_Tag_Component (Typ), Loc)),
+
+                       Right_Opnd =>
+                         Make_Selected_Component (Loc,
+                           Prefix =>
+                             Unchecked_Convert_To (Typ, New_Value (Param)),
+                           Selector_Name =>
+                             New_Reference_To
+                               (First_Tag_Component (Typ), Loc))),
+
+                   Then_Statements =>
+                     New_List (New_Constraint_Error (Loc))));
+            end if;
+
+            Next_Actual (Param);
+         end loop;
+      end if;
+   end Apply_Tag_Checks;
+
    ------------------------
    -- Building_Static_DT --
    ------------------------
@@ -469,8 +650,9 @@ package body Exp_Disp is
       --  Dispatching call to C++ primitive. Create a new parameter list
       --  with no tag checks.
 
+      New_Params := New_List;
+
       if Is_CPP_Class (Typ) then
-         New_Params := New_List;
          Param := First_Actual (Call_Node);
          while Present (Param) loop
             Append_To (New_Params, Relocate_Node (Param));
@@ -480,86 +662,19 @@ package body Exp_Disp is
       --  Dispatching call to Ada primitive
 
       elsif Present (Param_List) then
+         Apply_Tag_Checks (Call_Node);
 
-         --  Generate the Tag checks when appropriate
-
-         New_Params := New_List;
          Param := First_Actual (Call_Node);
          while Present (Param) loop
+            --  Cases in which we may have generated runtime checks
 
-            --  No tag check with itself
-
-            if Param = Ctrl_Arg then
-               Append_To (New_Params,
-                 Duplicate_Subexpr_Move_Checks (Param));
-
-            --  No tag check for parameter whose type is neither tagged nor
-            --  access to tagged (for access parameters)
-
-            elsif No (Find_Controlling_Arg (Param)) then
-               Append_To (New_Params, Relocate_Node (Param));
-
-            --  No tag check for function dispatching on result if the
-            --  Tag given by the context is this one
-
-            elsif Find_Controlling_Arg (Param) = Ctrl_Arg then
-               Append_To (New_Params, Relocate_Node (Param));
-
-            --  "=" is the only dispatching operation allowed to get
-            --  operands with incompatible tags (it just returns false).
-            --  We use Duplicate_Subexpr_Move_Checks instead of calling
-            --  Relocate_Node because the value will be duplicated to
-            --  check the tags.
-
-            elsif Subp = Eq_Prim_Op then
+            if Param = Ctrl_Arg
+              or else Subp = Eq_Prim_Op
+            then
                Append_To (New_Params,
                  Duplicate_Subexpr_Move_Checks (Param));
 
-            --  No check in presence of suppress flags
-
-            elsif Tag_Checks_Suppressed (Etype (Param))
-              or else (Is_Access_Type (Etype (Param))
-                         and then Tag_Checks_Suppressed
-                                    (Designated_Type (Etype (Param))))
-            then
-               Append_To (New_Params, Relocate_Node (Param));
-
-            --  Optimization: no tag checks if the parameters are identical
-
-            elsif Is_Entity_Name (Param)
-              and then Is_Entity_Name (Ctrl_Arg)
-              and then Entity (Param) = Entity (Ctrl_Arg)
-            then
-               Append_To (New_Params, Relocate_Node (Param));
-
-            --  Now we need to generate the Tag check
-
             else
-               --  Generate code for tag equality check
-               --  Perhaps should have Checks.Apply_Tag_Equality_Check???
-
-               Insert_Action (Ctrl_Arg,
-                 Make_Implicit_If_Statement (Call_Node,
-                   Condition =>
-                     Make_Op_Ne (Loc,
-                       Left_Opnd =>
-                         Make_Selected_Component (Loc,
-                           Prefix => New_Value (Ctrl_Arg),
-                           Selector_Name =>
-                             New_Reference_To
-                               (First_Tag_Component (Typ), Loc)),
-
-                       Right_Opnd =>
-                         Make_Selected_Component (Loc,
-                           Prefix =>
-                             Unchecked_Convert_To (Typ, New_Value (Param)),
-                           Selector_Name =>
-                             New_Reference_To
-                               (First_Tag_Component (Typ), Loc))),
-
-                   Then_Statements =>
-                     New_List (New_Constraint_Error (Loc))));
-
                Append_To (New_Params, Relocate_Node (Param));
             end if;
 
@@ -6192,6 +6307,21 @@ package body Exp_Disp is
       return Result;
    end Make_Tags;
 
+   ---------------
+   -- New_Value --
+   ---------------
+
+   function New_Value (From : Node_Id) return Node_Id is
+      Res : constant Node_Id := Duplicate_Subexpr (From);
+   begin
+      if Is_Access_Type (Etype (From)) then
+         return Make_Explicit_Dereference (Sloc (From),
+                  Prefix => Res);
+      else
+         return Res;
+      end if;
+   end New_Value;
+
    -----------------------------------
    -- Original_View_In_Visible_Part --
    -----------------------------------