From: Javier Miranda <[email protected]>

The patch enforces checks on access to interface type conversions
internally generated by the frontend to displace the pointer to
a tagged type object (pointer named "this" in the C++ terminology)
from a dispatch table to a another dispatch table.

gcc/ada/ChangeLog:

        * exp_util.ads (Flag_Interface_Pointer_Displacement): New subprogram.
        * exp_util.adb (Flag_Interface_Pointer_Displacement): Ditto.
        * exp_attr.adb (Add_Implicit_Interface_Type_Conversion): Flag type
        conversions internally added to displace the pointer to the object.
        (Expand_N_Attribute_Reference): Ditto.
        * exp_ch4.adb (Displace_Allocator_Pointer): Ditto.
        * exp_ch6.adb (Expand_Simple_Function_Return): Ditto.
        (Make_Build_In_Place_Call_In_Allocator): Ditto.
        (Make_CPP_Constructor_Call_In_Allocator): Ditto.
        * exp_disp.adb (Expand_Interface_Actuals): Ditto.
        * exp_intr.adb (Expand_Dispatching_Constructor_Call): Ditto.
        * sem_ch6.adb (Analyze_Function_Return): Ditto.
        * sem_disp.adb (Propagate_Tag): Ditto.
        * sem_res.adb (Resolve_Actuals): Ditto.
        (Valid_Conversion): Rely on the new flag to handle the type conversion
        as a conversion added to displace the pointer to the object. Factorize
        code handling general and anonymous access types.
        * sem_type.adb (Interface_Present_In_Ancestor): For concurrent types
        add missing handling of class-wide types. Noticed working on this
        issue.
        * sinfo.ads (Is_Interface_Pointer_Displacement): Document this new flag.
        * gen_il-fields.ads (Is_Interface_Pointer_Displacement): New flag.
        * gen_il-gen-gen_nodes.adb (Is_Interface_Pointer_Displacement): New
        flag on N_Type_Conversion nodes.
        * gen_il-internals.adb (Image): Add Is_Interface_Pointer_Displacement
        flag image.

Tested on x86_64-pc-linux-gnu, committed on master.

---
 gcc/ada/exp_attr.adb             |   4 ++
 gcc/ada/exp_ch4.adb              |   1 +
 gcc/ada/exp_ch6.adb              |   6 ++
 gcc/ada/exp_disp.adb             |   3 +
 gcc/ada/exp_intr.adb             |   4 ++
 gcc/ada/exp_util.adb             |  11 +++
 gcc/ada/exp_util.ads             |   7 ++
 gcc/ada/gen_il-fields.ads        |   1 +
 gcc/ada/gen_il-gen-gen_nodes.adb |   1 +
 gcc/ada/gen_il-internals.adb     |   2 +
 gcc/ada/sem_ch6.adb              |   2 +
 gcc/ada/sem_disp.adb             |   1 +
 gcc/ada/sem_res.adb              | 116 ++++---------------------------
 gcc/ada/sem_type.adb             |   7 +-
 gcc/ada/sinfo.ads                |   7 ++
 15 files changed, 69 insertions(+), 104 deletions(-)

diff --git a/gcc/ada/exp_attr.adb b/gcc/ada/exp_attr.adb
index f9436f78a41..8bf95095d1b 100644
--- a/gcc/ada/exp_attr.adb
+++ b/gcc/ada/exp_attr.adb
@@ -2651,6 +2651,7 @@ package body Exp_Attr is
                      Rewrite (Prefix (N),
                        Convert_To (Btyp_DDT,
                          New_Copy_Tree (Prefix (N))));
+                     Flag_Interface_Pointer_Displacement (Prefix (N));
 
                      Analyze_And_Resolve (Prefix (N), Btyp_DDT);
                   end if;
@@ -2675,6 +2676,8 @@ package body Exp_Attr is
                         Rewrite (N,
                           Convert_To (Typ,
                             New_Copy_Tree (Prefix (Ref_Object))));
+                        Flag_Interface_Pointer_Displacement (N);
+
                         Analyze_And_Resolve (N, Typ);
                      end if;
                   end;
@@ -3127,6 +3130,7 @@ package body Exp_Attr is
                              Designated_Type (Etype (Parent (N)));
             begin
                Rewrite (Pref, Convert_To (Iface_Typ, Relocate_Node (Pref)));
+               Flag_Interface_Pointer_Displacement (Pref);
                Analyze_And_Resolve (Pref, Iface_Typ);
                return;
             end;
diff --git a/gcc/ada/exp_ch4.adb b/gcc/ada/exp_ch4.adb
index 94944fcb032..2b52fc70175 100644
--- a/gcc/ada/exp_ch4.adb
+++ b/gcc/ada/exp_ch4.adb
@@ -548,6 +548,7 @@ package body Exp_Ch4 is
                --     the secondary dispatch table.
 
                Rewrite (N, Convert_To (Dtyp, Relocate_Node (N)));
+               Flag_Interface_Pointer_Displacement (N);
                Analyze_And_Resolve (N, Dtyp);
 
                --  3) The 'access to the secondary dispatch table will be used
diff --git a/gcc/ada/exp_ch6.adb b/gcc/ada/exp_ch6.adb
index 72288631d3d..eb141839a3e 100644
--- a/gcc/ada/exp_ch6.adb
+++ b/gcc/ada/exp_ch6.adb
@@ -7724,6 +7724,7 @@ package body Exp_Ch6 is
 
             if Is_Interface (R_Type) then
                Rewrite (Exp, Convert_To (R_Type, Relocate_Node (Exp)));
+               Flag_Interface_Pointer_Displacement (Exp);
             end if;
 
             Analyze_And_Resolve (Exp, R_Type);
@@ -7802,6 +7803,7 @@ package body Exp_Ch6 is
 
                if Is_Interface (R_Type) then
                   Rewrite (Exp, Convert_To (R_Type, Relocate_Node (Exp)));
+                  Flag_Interface_Pointer_Displacement (Exp);
                end if;
 
                Analyze_And_Resolve (Exp, R_Type);
@@ -7996,6 +7998,7 @@ package body Exp_Ch6 is
         and then Utyp /= Underlying_Type (Exp_Typ)
       then
          Rewrite (Exp, Convert_To (Utyp, Relocate_Node (Exp)));
+         Flag_Interface_Pointer_Displacement (Exp);
          Analyze_And_Resolve (Exp);
       end if;
 
@@ -9196,6 +9199,7 @@ package body Exp_Ch6 is
          Rewrite
            (Ref_Func_Call,
             OK_Convert_To (Acc_Type, Ref_Func_Call));
+         Flag_Interface_Pointer_Displacement (Ref_Func_Call);
 
       --  If the types are incompatible, we need an unchecked conversion. Note
       --  that the full types will be compatible, but the types not visibly
@@ -10002,6 +10006,7 @@ package body Exp_Ch6 is
       Rewrite (Allocator,
         Convert_To (Etype (Allocator),
           New_Occurrence_Of (Tmp_Id, Loc)));
+      Flag_Interface_Pointer_Displacement (Allocator);
    end Make_Build_In_Place_Iface_Call_In_Allocator;
 
    ---------------------------------------------------------
@@ -10219,6 +10224,7 @@ package body Exp_Ch6 is
 
       if Is_Interface (Designated_Type (Acc_Type)) then
          Rewrite (Allocator, Convert_To (Acc_Type, Relocate_Node (Allocator)));
+         Flag_Interface_Pointer_Displacement (Allocator);
       end if;
 
       Analyze_And_Resolve (Allocator, Acc_Type);
diff --git a/gcc/ada/exp_disp.adb b/gcc/ada/exp_disp.adb
index ea3706fe8c7..f19ccac11d0 100644
--- a/gcc/ada/exp_disp.adb
+++ b/gcc/ada/exp_disp.adb
@@ -1708,6 +1708,7 @@ package body Exp_Disp is
                end if;
 
                Conversion := Convert_To (Formal_Typ, Relocate_Node (Actual));
+               Flag_Interface_Pointer_Displacement (Conversion);
                Rewrite (Actual, Conversion);
                Analyze_And_Resolve (Actual, Formal_Typ);
             end if;
@@ -1776,6 +1777,8 @@ package body Exp_Disp is
 
                Conversion := Convert_To (Formal_Typ, Actual_Dup);
                Rewrite (Actual, Conversion);
+               Flag_Interface_Pointer_Displacement (Actual);
+
                Analyze_And_Resolve (Actual, Formal_Typ);
             end if;
          end if;
diff --git a/gcc/ada/exp_intr.adb b/gcc/ada/exp_intr.adb
index bb1e5816691..2949b9cc43f 100644
--- a/gcc/ada/exp_intr.adb
+++ b/gcc/ada/exp_intr.adb
@@ -415,6 +415,10 @@ package body Exp_Intr is
 
       Rewrite (N, Convert_To (Result_Typ, Cnstr_Call));
 
+      if Is_Interface (Result_Typ) then
+         Flag_Interface_Pointer_Displacement (N);
+      end if;
+
       --  Do not generate a run-time check on the built object if tag
       --  checks are suppressed for the result type or tagged type expansion
       --  is disabled or if CodePeer_Mode.
diff --git a/gcc/ada/exp_util.adb b/gcc/ada/exp_util.adb
index c5c70daac17..4dc4b03da68 100644
--- a/gcc/ada/exp_util.adb
+++ b/gcc/ada/exp_util.adb
@@ -7127,6 +7127,17 @@ package body Exp_Util is
       end if;
    end Find_Hook_Context;
 
+   -----------------------------------------
+   -- Flag_Interface_Pointer_Displacement --
+   -----------------------------------------
+
+   procedure Flag_Interface_Pointer_Displacement (N : Node_Id) is
+   begin
+      if Nkind (N) = N_Type_Conversion then
+         Set_Is_Interface_Pointer_Displacement (N);
+      end if;
+   end Flag_Interface_Pointer_Displacement;
+
    ------------------------------
    -- Following_Address_Clause --
    ------------------------------
diff --git a/gcc/ada/exp_util.ads b/gcc/ada/exp_util.ads
index b7d8a185f4b..c866acd76b8 100644
--- a/gcc/ada/exp_util.ads
+++ b/gcc/ada/exp_util.ads
@@ -680,6 +680,12 @@ package Exp_Util is
    --  be evaluated, for example if N is the right operand of a short circuit
    --  operator.
 
+   procedure Flag_Interface_Pointer_Displacement (N : Node_Id);
+   --  If N is an N_Type_Conversion node then flag N to indicate that this
+   --  type conversion was internally added to force the displacement of the
+   --  pointer to the object (pointer named "this" in the C++ terminology)
+   --  from a dispatch table to another dispatch table.
+
    function Following_Address_Clause (D : Node_Id) return Node_Id;
    --  D is the node for an object declaration. This function searches the
    --  current declarative part to look for an address clause for the object
@@ -1370,6 +1376,7 @@ private
    pragma Inline (Duplicate_Subexpr);
    pragma Inline (Find_Controlled_Prim_Op);
    pragma Inline (Find_Prim_Op);
+   pragma Inline (Flag_Interface_Pointer_Displacement);
    pragma Inline (Force_Evaluation);
    pragma Inline (Get_Mapped_Entity);
    pragma Inline (Is_Library_Level_Tagged_Type);
diff --git a/gcc/ada/gen_il-fields.ads b/gcc/ada/gen_il-fields.ads
index 9c10406d4b6..8e05c187474 100644
--- a/gcc/ada/gen_il-fields.ads
+++ b/gcc/ada/gen_il-fields.ads
@@ -263,6 +263,7 @@ package Gen_IL.Fields is
       Is_Implicit_With,
       Is_In_Discriminant_Check,
       Is_Initialization_Block,
+      Is_Interface_Pointer_Displacement,
       Is_Interpolated_String_Literal,
       Is_Known_Guaranteed_ABE,
       Is_Machine_Number,
diff --git a/gcc/ada/gen_il-gen-gen_nodes.adb b/gcc/ada/gen_il-gen-gen_nodes.adb
index e6e00ff986d..9334c98e394 100644
--- a/gcc/ada/gen_il-gen-gen_nodes.adb
+++ b/gcc/ada/gen_il-gen-gen_nodes.adb
@@ -476,6 +476,7 @@ begin -- Gen_IL.Gen.Gen_Nodes
         Sm (Do_Length_Check, Flag),
         Sm (Do_Overflow_Check, Flag),
         Sm (Float_Truncate, Flag),
+        Sm (Is_Interface_Pointer_Displacement, Flag),
         Sm (Tag_Propagated, Flag),
         Sm (Rounded_Result, Flag)));
 
diff --git a/gcc/ada/gen_il-internals.adb b/gcc/ada/gen_il-internals.adb
index 0595bc54fc1..cd0f715cbd5 100644
--- a/gcc/ada/gen_il-internals.adb
+++ b/gcc/ada/gen_il-internals.adb
@@ -315,6 +315,8 @@ package body Gen_IL.Internals is
             return "Is_Elaboration_Warnings_OK_Node";
          when Is_IEEE_Extended_Precision =>
             return "Is_IEEE_Extended_Precision";
+         when Is_Interface_Pointer_Displacement =>
+            return "Is_Interface_Pointer_Displacement";
          when Is_Known_Guaranteed_ABE =>
             return "Is_Known_Guaranteed_ABE";
          when Is_RACW_Stub_Type =>
diff --git a/gcc/ada/sem_ch6.adb b/gcc/ada/sem_ch6.adb
index a6db10512b6..0629dda91a9 100644
--- a/gcc/ada/sem_ch6.adb
+++ b/gcc/ada/sem_ch6.adb
@@ -886,6 +886,8 @@ package body Sem_Ch6 is
                                       Designated_Type (Etype (Expr)))
             then
                Rewrite (Expr, Convert_To (R_Type, Relocate_Node (Expr)));
+               Flag_Interface_Pointer_Displacement (Expr);
+
                Analyze (Expr);
             end if;
 
diff --git a/gcc/ada/sem_disp.adb b/gcc/ada/sem_disp.adb
index 4a940e7f30b..0e89af8f0a7 100644
--- a/gcc/ada/sem_disp.adb
+++ b/gcc/ada/sem_disp.adb
@@ -3324,6 +3324,7 @@ package body Sem_Disp is
                    Subtype_Mark =>
                      New_Occurrence_Of (Etype (Control), Sloc (Call_Node)),
                    Expression => Relocate_Node (Call_Node)));
+               Flag_Interface_Pointer_Displacement (Call_Node);
                Set_Etype (Call_Node, Etype (Control));
                Set_Analyzed (Call_Node);
 
diff --git a/gcc/ada/sem_res.adb b/gcc/ada/sem_res.adb
index 885f51fe012..a0287f1abe5 100644
--- a/gcc/ada/sem_res.adb
+++ b/gcc/ada/sem_res.adb
@@ -4561,6 +4561,8 @@ package body Sem_Res is
                        and then Is_Interface (DDT)
                      then
                         Rewrite (A, Convert_To (Etype (F), Relocate_Node (A)));
+                        Flag_Interface_Pointer_Displacement (A);
+
                         Analyze_And_Resolve (A, Etype (F),
                           Suppress => Access_Check);
                      end if;
@@ -14325,111 +14327,13 @@ package body Sem_Res is
       --  reference the corresponding dispatch table.
 
       elsif not Comes_From_Source (N)
+         and then Nkind (N) = N_Type_Conversion
          and then Is_Access_Type (Target_Type)
          and then Is_Interface (Designated_Type (Target_Type))
+         and then Is_Interface_Pointer_Displacement (N)
       then
          return True;
 
-      --  Ada 2005 (AI-251): Anonymous access types where target references an
-      --  interface type.
-
-      elsif Is_Access_Type (Opnd_Type)
-        and then Ekind (Target_Type) in
-                   E_General_Access_Type | E_Anonymous_Access_Type
-        and then Is_Interface (Directly_Designated_Type (Target_Type))
-      then
-         --  Check the static accessibility rule of 4.6(17). Note that the
-         --  check is not enforced when within an instance body, since the
-         --  RM requires such cases to be caught at run time.
-
-         --  If the operand is a rewriting of an allocator no check is needed
-         --  because there are no accessibility issues.
-
-         if Nkind (Original_Node (N)) = N_Allocator then
-            null;
-
-         elsif Ekind (Target_Type) /= E_Anonymous_Access_Type then
-            if Type_Access_Level (Opnd_Type) >
-               Deepest_Type_Access_Level (Target_Type)
-            then
-               --  In an instance, this is a run-time check, but one we know
-               --  will fail, so generate an appropriate warning. The raise
-               --  will be generated by Expand_N_Type_Conversion.
-
-               if In_Instance_Body then
-                  Error_Msg_Warn := SPARK_Mode /= On;
-                  Report_Error_N
-                    ("cannot convert local pointer to non-local access type<<",
-                     Operand, Report_Errs);
-                  Report_Error_N ("\Program_Error [<<", Operand, Report_Errs);
-
-               else
-                  Report_Error_N
-                    ("cannot convert local pointer to non-local access type",
-                     Operand, Report_Errs);
-                  return False;
-               end if;
-
-            --  Special accessibility checks are needed in the case of access
-            --  discriminants declared for a limited type.
-
-            elsif Ekind (Opnd_Type) = E_Anonymous_Access_Type
-              and then not Is_Local_Anonymous_Access (Opnd_Type)
-            then
-               --  When the operand is a selected access discriminant the check
-               --  needs to be made against the level of the object denoted by
-               --  the prefix of the selected name (Accessibility_Level handles
-               --  checking the prefix of the operand for this case).
-
-               if Nkind (Operand) = N_Selected_Component
-                 and then Static_Accessibility_Level
-                            (Operand, Zero_On_Dynamic_Level)
-                              > Deepest_Type_Access_Level (Target_Type)
-               then
-                  --  In an instance, this is a run-time check, but one we know
-                  --  will fail, so generate an appropriate warning. The raise
-                  --  will be generated by Expand_N_Type_Conversion.
-
-                  if In_Instance_Body then
-                     Error_Msg_Warn := SPARK_Mode /= On;
-                     Report_Error_N
-                       ("cannot convert access discriminant to non-local "
-                        & "access type<<", Operand, Report_Errs);
-                     Report_Error_N
-                       ("\Program_Error [<<", Operand, Report_Errs);
-
-                  --  Real error if not in instance body
-
-                  else
-                     Report_Error_N
-                       ("cannot convert access discriminant to non-local "
-                        & "access type", Operand, Report_Errs);
-                     return False;
-                  end if;
-               end if;
-
-               --  The case of a reference to an access discriminant from
-               --  within a limited type declaration (which will appear as
-               --  a discriminal) is always illegal because the level of the
-               --  discriminant is considered to be deeper than any (nameable)
-               --  access type.
-
-               if Is_Entity_Name (Operand)
-                 and then not Is_Local_Anonymous_Access (Opnd_Type)
-                 and then
-                   Ekind (Entity (Operand)) in E_In_Parameter | E_Constant
-                 and then Present (Discriminal_Link (Entity (Operand)))
-               then
-                  Report_Error_N
-                    ("discriminant has deeper accessibility level than target",
-                     Operand, Report_Errs);
-                  return False;
-               end if;
-            end if;
-         end if;
-
-         return True;
-
       --  General and anonymous access types
 
       elsif Ekind (Target_Type) in
@@ -14484,10 +14388,16 @@ package body Sem_Res is
          end;
 
          --  Check the static accessibility rule of 4.6(17). Note that the
-         --  check is not enforced when within an instance body, since the RM
-         --  requires such cases to be caught at run time.
+         --  check is not enforced when within an instance body, since the
+         --  RM requires such cases to be caught at run time.
 
-         if Ekind (Target_Type) /= E_Anonymous_Access_Type
+         --  If the operand is a rewriting of an allocator no check is needed
+         --  because there are no accessibility issues.
+
+         if Nkind (Original_Node (N)) = N_Allocator then
+            null;
+
+         elsif Ekind (Target_Type) /= E_Anonymous_Access_Type
            or else Is_Local_Anonymous_Access (Target_Type)
            or else Nkind (Associated_Node_For_Itype (Target_Type)) =
                      N_Object_Declaration
diff --git a/gcc/ada/sem_type.adb b/gcc/ada/sem_type.adb
index 86fd0012492..ceaed45efcf 100644
--- a/gcc/ada/sem_type.adb
+++ b/gcc/ada/sem_type.adb
@@ -2685,7 +2685,12 @@ package body Sem_Type is
       end if;
 
       if Is_Concurrent_Record_Type (Target_Typ) then
-         Target_Typ := Corresponding_Concurrent_Type (Target_Typ);
+         if Is_Class_Wide_Type (Target_Typ) then
+            Target_Typ :=
+              Corresponding_Concurrent_Type (Root_Type (Target_Typ));
+         else
+            Target_Typ := Corresponding_Concurrent_Type (Target_Typ);
+         end if;
       end if;
 
       Target_Typ := Base_Type (Target_Typ);
diff --git a/gcc/ada/sinfo.ads b/gcc/ada/sinfo.ads
index 8a35fdc4208..c5d981d5302 100644
--- a/gcc/ada/sinfo.ads
+++ b/gcc/ada/sinfo.ads
@@ -1739,6 +1739,12 @@ package Sinfo is
    --    composed of interpolated string elements from string literals found
    --    in interpolated expressions.
 
+   --  Is_Interface_Pointer_Displacement
+   --    This flag is set in N_Type_Conversion nodes, and is used to indicate
+   --    that the type conversion was generated to displace the pointer to one
+   --    tagged object (pointer named "this" in the C++ terminology) from a
+   --    dispatch table to another dispatch table.
+
    --  Is_Known_Guaranteed_ABE
    --    Note: this flag is shared between the legacy ABE mechanism and the
    --    default ABE mechanism.
@@ -4757,6 +4763,7 @@ package Sinfo is
       --  Do_Overflow_Check
       --  Rounded_Result
       --  Tag_Propagated
+      --  Is_Interface_Pointer_Displacement
       --  plus fields for expression
 
       --  Note: if a range check is required, then the Do_Range_Check flag
-- 
2.51.0

Reply via email to