The compiler does not reject a type conversion of an object of
of a private type that is derived from an interface type if the
target type of the conversion is one of the parents of the
full type declaration of the private type (which breaks the
privacy contract imposed by the private type). The following
test must compile with one error:
package Types_1 is
type Iface is interface;
type A_Root is tagged null record;
type Typ1 is new A_Root and Iface with null record;
type Typ1_Access is access all Typ1'Class;
end;
with Types_1; use Types_1;
package Types_2 is
type Typ2 is new Iface with private; -- [1]
type Typ2_Access is access all Typ2'Class;
private
type Typ2 is new Typ1 with null record; -- [2]
end;
with Types_1; use Types_1;
with Types_2; use Types_2;
procedure Main is
M : Typ2_Access := new Typ2;
Bug : Typ1_Access := Typ1_Access (M); -- [3]: Error
begin
null;
end Main;
At [1] the private type declaration of Typ2 does not provide information
Gindicating that its full view (at [2]) is a derivation of Typ1. Hence,
the type conversion (at [3]) must be rejected by the compiler.
Command: gcc -c -gnat05 main.adb
Output: invalid tagged conversion, not compatible with type "Typ2'Class"
defined at types_2.ads:3
Tested on x86_64-pc-linux-gnu, committed on trunk
2011-08-02 Javier Miranda <[email protected]>
* sem_type.ads, sem_type.adb (Is_Ancestor): Addition of a new formal
(Use_Full_View) which permits this routine to climb through the
ancestors using the full-view of private parents.
* sem_util.adb (Collect_Interfaces_Info, Implements_Interface): Set
Use_Full_View to true in calls to Is_Ancestor.
* sem_disp.adb (Override_Dispatching_Operation): Set Use_Full_View to
true in call to Is_Ancestor.
* exp_ch3.adb (Build_Offset_To_Top_Functions, Initialize_Tag): Set
Use_Full_View to true in call to Is_Ancestor.
* exp_ch7.adb (Controller_Component): Set Use_Full_View to true in
call to Is_Ancestor.
* exp_ch4.adb (Expand_N_Type_Conversion, Tagged_Membership): Set
Use_Full_View to true in calls to Is_Ancestor.
* exp_disp.adb (Expand_Interface_Actuals, Make_Secondary_DT, Make_DT,
Make_Select_Specific_Data_Table, Register_Primitive,
Set_All_DT_Position): Set Use_Full_View to true in calls to Is_Ancestor.
* exp_intr.adb (Expand_Dispatching_Constructor_Call): Set Use_Full_View
to true in call to Is_Ancestor.
* exp_util.adb (Find_Interface_ADT, Find_Interface_Tag): Set
Use_Full_View to true in calls to Is_Ancestor.
* exp_cg.adb
(Write_Call_Info): Set Use_Full_View to true in call to Is_Ancestor.
(Write_Type_Info): Set Use_Full_View to true in call to Is_Ancestor.
Index: exp_ch7.adb
===================================================================
--- exp_ch7.adb (revision 177035)
+++ exp_ch7.adb (working copy)
@@ -911,7 +911,9 @@ package body Exp_Ch7 is
-- Otherwise record the outermost one and continue looking
- elsif Res = Empty or else Is_Ancestor (Res_Scop, Comp_Scop) then
+ elsif Res = Empty
+ or else Is_Ancestor (Res_Scop, Comp_Scop, Use_Full_View => True)
+ then
Res := Comp;
Res_Scop := Comp_Scop;
end if;
Index: sem_type.adb
===================================================================
--- sem_type.adb (revision 176998)
+++ sem_type.adb (working copy)
@@ -2564,7 +2564,11 @@ package body Sem_Type is
-- Is_Ancestor --
-----------------
- function Is_Ancestor (T1, T2 : Entity_Id) return Boolean is
+ function Is_Ancestor
+ (T1 : Entity_Id;
+ T2 : Entity_Id;
+ Use_Full_View : Boolean := False) return Boolean
+ is
BT1 : Entity_Id;
BT2 : Entity_Id;
Par : Entity_Id;
@@ -2624,14 +2628,14 @@ package body Sem_Type is
then
return True;
+ -- Climb to the ancestor type
+
elsif Etype (Par) /= Par then
- -- If this is a private type and its parent is an interface
- -- then use the parent of the full view (which is a type that
- -- implements such interface)
+ -- Use the full-view of private types (if allowed)
- if Is_Private_Type (Par)
- and then Is_Interface (Etype (Par))
+ if Use_Full_View
+ and then Is_Private_Type (Par)
and then Present (Full_View (Par))
then
Par := Etype (Full_View (Par));
Index: sem_type.ads
===================================================================
--- sem_type.ads (revision 176998)
+++ sem_type.ads (working copy)
@@ -217,9 +217,23 @@ package Sem_Type is
-- but conceptually the resolution of the actual takes place in the
-- enclosing context and no special disambiguation rules should be applied.
- function Is_Ancestor (T1, T2 : Entity_Id) return Boolean;
+ function Is_Ancestor
+ (T1 : Entity_Id;
+ T2 : Entity_Id;
+ Use_Full_View : Boolean := False) return Boolean;
-- T1 is a tagged type (not class-wide). Verify that it is one of the
- -- ancestors of type T2 (which may or not be class-wide).
+ -- ancestors of type T2 (which may or not be class-wide). If Use_Full_View
+ -- is True then the full-view of private parents is used when climbing
+ -- through the parents of T2.
+ --
+ -- Note: For analysis purposes the flag Use_Full_View must be set to False
+ -- (otherwise we break the privacy contract since this routine returns true
+ -- for hidden ancestors of private types). For expansion purposes this flag
+ -- is generally set to True since the expander must know with precision the
+ -- ancestors of a tagged type. For example, if a private type derives from
+ -- an interface type then the interface may not be an ancestor of its full
+ -- view since the full-view is only required to cover the interface (RM 7.3
+ -- (7.3/2))) and this knowledge affects construction of dispatch tables.
function Is_Progenitor
(Iface : Entity_Id;
Index: exp_util.adb
===================================================================
--- exp_util.adb (revision 177027)
+++ exp_util.adb (working copy)
@@ -1501,7 +1501,7 @@ package body Exp_Util is
(not Is_Class_Wide_Type (Typ)
and then Ekind (Typ) /= E_Incomplete_Type);
- if Is_Ancestor (Iface, Typ) then
+ if Is_Ancestor (Iface, Typ, Use_Full_View => True) then
return First_Elmt (Access_Disp_Table (Typ));
else
@@ -1510,7 +1510,8 @@ package body Exp_Util is
while Present (ADT)
and then Present (Related_Type (Node (ADT)))
and then Related_Type (Node (ADT)) /= Iface
- and then not Is_Ancestor (Iface, Related_Type (Node (ADT)))
+ and then not Is_Ancestor (Iface, Related_Type (Node (ADT)),
+ Use_Full_View => True)
loop
Next_Elmt (ADT);
end loop;
@@ -1576,7 +1577,9 @@ package body Exp_Util is
while Present (AI_Elmt) loop
AI := Node (AI_Elmt);
- if AI = Iface or else Is_Ancestor (Iface, AI) then
+ if AI = Iface
+ or else Is_Ancestor (Iface, AI, Use_Full_View => True)
+ then
Found := True;
return;
end if;
@@ -1628,7 +1631,7 @@ package body Exp_Util is
-- If the interface is an ancestor of the type, then it shared the
-- primary dispatch table.
- if Is_Ancestor (Iface, Typ) then
+ if Is_Ancestor (Iface, Typ, Use_Full_View => True) then
pragma Assert (Etype (First_Tag_Component (Typ)) = RTE (RE_Tag));
return First_Tag_Component (Typ);
Index: sem_util.adb
===================================================================
--- sem_util.adb (revision 177061)
+++ sem_util.adb (working copy)
@@ -1687,7 +1687,7 @@ package body Sem_Util is
-- Associate the primary tag component and the primary dispatch table
-- with all the interfaces that are parents of T
- if Is_Ancestor (Iface, T) then
+ if Is_Ancestor (Iface, T, Use_Full_View => True) then
Append_Elmt (First_Tag_Component (T), Components_List);
Append_Elmt (Node (First_Elmt (Access_Disp_Table (T))), Tags_List);
@@ -1700,7 +1700,7 @@ package body Sem_Util is
Comp_Iface := Related_Type (Node (Comp_Elmt));
if Comp_Iface = Iface
- or else Is_Ancestor (Iface, Comp_Iface)
+ or else Is_Ancestor (Iface, Comp_Iface, Use_Full_View => True)
then
Append_Elmt (Node (Comp_Elmt), Components_List);
Append_Elmt (Search_Tag (Comp_Iface), Tags_List);
@@ -5504,7 +5504,7 @@ package body Sem_Util is
Elmt := First_Elmt (Ifaces_List);
while Present (Elmt) loop
- if Is_Ancestor (Node (Elmt), Typ)
+ if Is_Ancestor (Node (Elmt), Typ, Use_Full_View => True)
and then Exclude_Parents
then
null;
Index: exp_ch4.adb
===================================================================
--- exp_ch4.adb (revision 177059)
+++ exp_ch4.adb (working copy)
@@ -8628,7 +8628,8 @@ package body Exp_Ch4 is
if Is_Class_Wide_Type (Actual_Op_Typ)
and then Actual_Op_Typ /= Actual_Targ_Typ
and then Root_Op_Typ /= Actual_Targ_Typ
- and then Is_Ancestor (Root_Op_Typ, Actual_Targ_Typ)
+ and then Is_Ancestor (Root_Op_Typ, Actual_Targ_Typ,
+ Use_Full_View => True)
then
Make_Tag_Check (Class_Wide_Type (Actual_Targ_Typ));
Make_Conversion := True;
@@ -10461,7 +10462,8 @@ package body Exp_Ch4 is
-- Obj1 in Iface'Class; -- Compile time error
if not Is_Class_Wide_Type (Left_Type)
- and then (Is_Ancestor (Etype (Right_Type), Left_Type)
+ and then (Is_Ancestor (Etype (Right_Type), Left_Type,
+ Use_Full_View => True)
or else (Is_Interface (Etype (Right_Type))
and then Interface_Present_In_Ancestor
(Typ => Left_Type,
Index: exp_disp.adb
===================================================================
--- exp_disp.adb (revision 177047)
+++ exp_disp.adb (working copy)
@@ -1435,7 +1435,9 @@ package body Exp_Disp is
-- a parent of the type of the actual because in this case the
-- interface primitives are located in the primary dispatch table.
- elsif Is_Ancestor (Formal_Typ, Actual_Typ) then
+ elsif Is_Ancestor (Formal_Typ, Actual_Typ,
+ Use_Full_View => True)
+ then
null;
-- Implicit conversion to the class-wide formal type to force
@@ -1494,7 +1496,9 @@ package body Exp_Disp is
-- a parent of the type of the actual because in this case the
-- interface primitives are located in the primary dispatch table.
- elsif Is_Ancestor (Formal_DDT, Actual_DDT) then
+ elsif Is_Ancestor (Formal_DDT, Actual_DDT,
+ Use_Full_View => True)
+ then
null;
else
@@ -4090,7 +4094,8 @@ package body Exp_Disp is
-- Tagged_Type. Otherwise the DT associated with the
-- interface is the primary DT.
- and then not Is_Ancestor (Iface, Typ)
+ and then not Is_Ancestor (Iface, Typ,
+ Use_Full_View => True)
then
if not Build_Thunks then
Prim_Pos :=
@@ -5087,7 +5092,7 @@ package body Exp_Disp is
begin
AI := First_Elmt (Typ_Ifaces);
while Present (AI) loop
- if Is_Ancestor (Node (AI), Typ) then
+ if Is_Ancestor (Node (AI), Typ, Use_Full_View => True) then
Sec_DT_Tag :=
New_Reference_To (DT_Ptr, Loc);
else
@@ -5098,7 +5103,8 @@ package body Exp_Disp is
while Is_Tag (Node (Elmt))
and then not
- Is_Ancestor (Node (AI), Related_Type (Node (Elmt)))
+ Is_Ancestor (Node (AI), Related_Type (Node (Elmt)),
+ Use_Full_View => True)
loop
pragma Assert (Has_Thunks (Node (Elmt)));
Next_Elmt (Elmt);
@@ -6182,7 +6188,8 @@ package body Exp_Disp is
if Present (Interface_Alias (Prim))
and then not
Is_Ancestor
- (Find_Dispatching_Type (Interface_Alias (Prim)), Typ)
+ (Find_Dispatching_Type (Interface_Alias (Prim)), Typ,
+ Use_Full_View => True)
and then not Examined (UI_To_Int (DT_Position (Alias (Prim))))
then
Prim_Pos := DT_Position (Alias (Prim));
@@ -6983,7 +6990,7 @@ package body Exp_Disp is
-- No action needed for interfaces that are ancestors of Typ because
-- their primitives are located in the primary dispatch table.
- if Is_Ancestor (Iface_Typ, Tag_Typ) then
+ if Is_Ancestor (Iface_Typ, Tag_Typ, Use_Full_View => True) then
return L;
-- No action needed for primitives located in the C++ part of the
@@ -6999,7 +7006,7 @@ package body Exp_Disp is
Expand_Interface_Thunk (Prim, Thunk_Id, Thunk_Code);
- if not Is_Ancestor (Iface_Typ, Tag_Typ)
+ if not Is_Ancestor (Iface_Typ, Tag_Typ, Use_Full_View => True)
and then Present (Thunk_Code)
then
-- Generate the code necessary to fill the appropriate entry of
@@ -7357,7 +7364,8 @@ package body Exp_Disp is
elsif Present (Interface_Alias (Prim))
and then Is_Ancestor
- (Find_Dispatching_Type (Interface_Alias (Prim)), Typ)
+ (Find_Dispatching_Type (Interface_Alias (Prim)), Typ,
+ Use_Full_View => True)
then
pragma Assert (DT_Position (Prim) = No_Uint
and then Present (DTC_Entity (Interface_Alias (Prim))));
@@ -7379,7 +7387,8 @@ package body Exp_Disp is
and then Chars (Prim) = Chars (Alias (Prim))
and then Find_Dispatching_Type (Alias (Prim)) /= Typ
and then Is_Ancestor
- (Find_Dispatching_Type (Alias (Prim)), Typ)
+ (Find_Dispatching_Type (Alias (Prim)), Typ,
+ Use_Full_View => True)
and then Present (DTC_Entity (Alias (Prim)))
then
E := Alias (Prim);
@@ -7445,7 +7454,8 @@ package body Exp_Disp is
-- Check if this entry will be placed in the primary DT
if Is_Ancestor
- (Find_Dispatching_Type (Interface_Alias (Prim)), Typ)
+ (Find_Dispatching_Type (Interface_Alias (Prim)), Typ,
+ Use_Full_View => True)
then
pragma Assert (DT_Position (Alias (Prim)) /= No_Uint);
Set_DT_Position (Prim, DT_Position (Alias (Prim)));
Index: exp_intr.adb
===================================================================
--- exp_intr.adb (revision 176998)
+++ exp_intr.adb (working copy)
@@ -231,7 +231,9 @@ package body Exp_Intr is
-- If the result type is not parent of Tag_Arg then we need to
-- locate the tag of the secondary dispatch table.
- if not Is_Ancestor (Etype (Result_Typ), Etype (Tag_Arg)) then
+ if not Is_Ancestor (Etype (Result_Typ), Etype (Tag_Arg),
+ Use_Full_View => True)
+ then
pragma Assert (not Is_Interface (Etype (Tag_Arg)));
Iface_Tag :=
Index: exp_cg.adb
===================================================================
--- exp_cg.adb (revision 176998)
+++ exp_cg.adb (working copy)
@@ -478,7 +478,8 @@ package body Exp_CG is
and then
Is_Ancestor
(Find_Dispatching_Type (Ultimate_Alias (Prim)),
- Root_Type (Ctrl_Typ))
+ Root_Type (Ctrl_Typ),
+ Use_Full_View => True)
then
-- This is a special case in which we generate in the ci file the
-- slot number of the renaming primitive (i.e. Base2) but instead of
@@ -616,7 +617,8 @@ package body Exp_CG is
if Present (Overridden_Operation (Prim))
and then
Is_Ancestor
- (Find_Dispatching_Type (Overridden_Operation (Prim)), Typ)
+ (Find_Dispatching_Type (Overridden_Operation (Prim)), Typ,
+ Use_Full_View => True)
then
Write_Char (',');
Write_Int
@@ -642,7 +644,8 @@ package body Exp_CG is
if Present (Int_Alias)
and then
- not Is_Ancestor (Find_Dispatching_Type (Int_Alias), Typ)
+ not Is_Ancestor (Find_Dispatching_Type (Int_Alias), Typ,
+ Use_Full_View => True)
and then (Alias (Prim_Op)) = Prim
then
Write_Char (',');
Index: sem_disp.adb
===================================================================
--- sem_disp.adb (revision 177059)
+++ sem_disp.adb (working copy)
@@ -2087,7 +2087,7 @@ package body Sem_Disp is
and then Etype (Tagged_Type) /= Tagged_Type
and then Is_Interface (Find_Dispatching_Type (Alias (Prev_Op)))
and then not Is_Ancestor (Find_Dispatching_Type (Alias (Prev_Op)),
- Tagged_Type)
+ Tagged_Type, Use_Full_View => True)
and then not Implements_Interface
(Etype (Tagged_Type),
Find_Dispatching_Type (Alias (Prev_Op)))
Index: exp_ch3.adb
===================================================================
--- exp_ch3.adb (revision 177051)
+++ exp_ch3.adb (working copy)
@@ -2220,7 +2220,9 @@ package body Exp_Ch3 is
-- If the interface is a parent of Rec_Type it shares the primary
-- dispatch table and hence there is no need to build the function
- if not Is_Ancestor (Related_Type (Iface_Comp), Rec_Type) then
+ if not Is_Ancestor (Related_Type (Iface_Comp), Rec_Type,
+ Use_Full_View => True)
+ then
Build_Offset_To_Top_Function (Iface_Comp);
end if;
@@ -7297,7 +7299,7 @@ package body Exp_Ch3 is
-- Initialize the pointer to the secondary DT associated with the
-- interface.
- if not Is_Ancestor (Iface, Typ) then
+ if not Is_Ancestor (Iface, Typ, Use_Full_View => True) then
Append_To (Stmts_List,
Make_Assignment_Statement (Loc,
Name =>
@@ -7394,7 +7396,7 @@ package body Exp_Ch3 is
-- Don't need to set any value if this interface shares
-- the primary dispatch table.
- if not Is_Ancestor (Iface, Typ) then
+ if not Is_Ancestor (Iface, Typ, Use_Full_View => True) then
Append_To (Stmts_List,
Build_Set_Static_Offset_To_Top (Loc,
Iface_Tag => New_Reference_To (Iface_Tag, Loc),