This patch improves the support for interface conversions in the .NET/JVM compiler extending the current support for attribute 'tag and adding the missing runtime checks required in interface conversions when the tag of the source is unknown at compile time. After this patch the following test compiles and executes well.
with GNAT.IO; use GNAT.IO; procedure Main is package Pkg is type Iface is interface; procedure Print (Obj : in out Iface) is abstract; type Parent is tagged record Id : Natural := 1; end record; type Child is new Parent and Iface with null record; procedure Print (Obj : in out Child); function New_Child return Iface'Class; end Pkg; package body Pkg is procedure Print (Obj : in out Child) is begin Put_Line ("child" & Obj.Id'Img); end Print; function New_Child return Iface'Class is begin return Obj : Child do Obj.Id := 3; end return; end New_Child; end Pkg; use Pkg; C : Iface'Class := New_Child; begin Print (C); end Main; Command: dotnet-gnatmake -gnat05 main; ./main.exe Output: child 3 Tested on x86_64-pc-linux-gnu, committed on trunk 2011-08-04 Javier Miranda <mira...@adacore.com> * exp_ch7.adb (Expand_N_Package_Body, Expand_N_Package_Declaration): Remove code which takes care of building TSDs. * rtsfind.ads (RE_Check_Interface_Conversion): New entity. * exp_ch4.adb (Apply_Accessibility_Check): Add support for generating the accessibility check in VM targets. * exp_disp.adb (Make_VM_TSD): Spec moved to exp_disp.ads (Building_Static_DT): Now returns false for VM targets. (Build_VM_TSDs): Removed. (Expand_Interface_Conversion): Generate missing runtime check for conversions to interface types whose target type is unknown at compile time. (Make_VM_TSD): Add missing code to disable the generation of calls to Check_TSD if the tagged type is not defined at library level, or not has a representation clause specifying its external tag, or -gnatdQ is active. * exp_disp.ads (Build_VM_TSDs): Removed. (Make_VM_TSDs): Spec relocated from exp_disp.adb * sem_disp.adb (Check_Dispatching_Operation): No code required to register primitives in the dispatch tables in VM targets. * exp_ch3.adb (Expand_N_Object_Declaration): Remove wrong expansion of initialization of class-wide interface objects in VM targets. (Expand_Freeze_Record_Type): For VM targets call Make_VM_TSD (instead of Make_DT).
Index: exp_ch7.adb =================================================================== --- exp_ch7.adb (revision 177386) +++ exp_ch7.adb (working copy) @@ -1261,7 +1261,7 @@ -- objects that need finalization. When flag Preprocess is set, the -- routine will simply count the total number of controlled objects in -- Decls. Flag Top_Level denotes whether the processing is done for - -- objects in nested package decparations or instances. + -- objects in nested package declarations or instances. procedure Process_Object_Declaration (Decl : Node_Id; @@ -3810,24 +3810,10 @@ -- Build dispatch tables of library level tagged types - if Is_Library_Level_Entity (Spec_Ent) then - if Tagged_Type_Expansion then - Build_Static_Dispatch_Tables (N); - - -- In VM targets there is no need to build dispatch tables but - -- we must generate the corresponding Type Specific Data record. - - elsif Unit (Cunit (Main_Unit)) = N then - - -- If the runtime package Ada_Tags has not been loaded then - -- this package does not have tagged type declarations and - -- there is no need to search for tagged types to generate - -- their TSDs. - - if RTU_Loaded (Ada_Tags) then - Build_VM_TSDs (N); - end if; - end if; + if Tagged_Type_Expansion + and then Is_Library_Level_Entity (Spec_Ent) + then + Build_Static_Dispatch_Tables (N); end if; Build_Task_Activation_Call (N); @@ -3948,42 +3934,12 @@ -- Build dispatch tables of library level tagged types - if Is_Compilation_Unit (Id) - or else (Is_Generic_Instance (Id) - and then Is_Library_Level_Entity (Id)) + if Tagged_Type_Expansion + and then (Is_Compilation_Unit (Id) + or else (Is_Generic_Instance (Id) + and then Is_Library_Level_Entity (Id))) then - if Tagged_Type_Expansion then - Build_Static_Dispatch_Tables (N); - - -- In VM targets there is no need to build dispatch tables, but we - -- must generate the corresponding Type Specific Data record. - - elsif Unit (Cunit (Main_Unit)) = N then - - -- If the runtime package Ada_Tags has not been loaded then - -- this package does not have tagged types and there is no need - -- to search for tagged types to generate their TSDs. - - if RTU_Loaded (Ada_Tags) then - - -- Enter the scope of the package because the new declarations - -- are appended at the end of the package and must be analyzed - -- in that context. - - Push_Scope (Id); - - if Is_Generic_Instance (Main_Unit_Entity) then - if Package_Instantiation (Main_Unit_Entity) = N then - Build_VM_TSDs (N); - end if; - - else - Build_VM_TSDs (N); - end if; - - Pop_Scope; - end if; - end if; + Build_Static_Dispatch_Tables (N); end if; -- Note: it is not necessary to worry about generating a subprogram Index: rtsfind.ads =================================================================== --- rtsfind.ads (revision 177378) +++ rtsfind.ads (working copy) @@ -561,6 +561,7 @@ RE_Address_Array, -- Ada.Tags RE_Addr_Ptr, -- Ada.Tags RE_Base_Address, -- Ada.Tags + RE_Check_Interface_Conversion, -- Ada.Tags RE_Check_TSD, -- Ada.Tags RE_Cstring_Ptr, -- Ada.Tags RE_Descendant_Tag, -- Ada.Tags @@ -1743,6 +1744,7 @@ RE_Address_Array => Ada_Tags, RE_Addr_Ptr => Ada_Tags, RE_Base_Address => Ada_Tags, + RE_Check_Interface_Conversion => Ada_Tags, RE_Check_TSD => Ada_Tags, RE_Cstring_Ptr => Ada_Tags, RE_Descendant_Tag => Ada_Tags, Index: exp_ch4.adb =================================================================== --- exp_ch4.adb (revision 177365) +++ exp_ch4.adb (working copy) @@ -629,14 +629,10 @@ (Ref : Node_Id; Built_In_Place : Boolean := False) is - Ref_Node : Node_Id; + New_Node : Node_Id; begin - -- Note: we skip the accessibility check for the VM case, since - -- there does not seem to be any practical way of implementing it. - if Ada_Version >= Ada_2005 - and then Tagged_Type_Expansion and then Is_Class_Wide_Type (DesigT) and then not Scope_Suppress (Accessibility_Check) and then @@ -652,20 +648,37 @@ -- address of the allocated object. if Built_In_Place then - Ref_Node := New_Copy (Ref); + New_Node := New_Copy (Ref); else - Ref_Node := New_Reference_To (Ref, Loc); + New_Node := New_Reference_To (Ref, Loc); end if; + New_Node := + Make_Attribute_Reference (Loc, + Prefix => New_Node, + Attribute_Name => Name_Tag); + + if Tagged_Type_Expansion then + New_Node := + Build_Get_Access_Level (Loc, New_Node); + + elsif VM_Target /= No_VM then + New_Node := + Make_Function_Call (Loc, + Name => New_Reference_To (RTE (RE_Get_Access_Level), Loc), + Parameter_Associations => New_List (New_Node)); + + -- Cannot generate the runtime check + + else + return; + end if; + Insert_Action (N, Make_Raise_Program_Error (Loc, Condition => Make_Op_Gt (Loc, - Left_Opnd => - Build_Get_Access_Level (Loc, - Make_Attribute_Reference (Loc, - Prefix => Ref_Node, - Attribute_Name => Name_Tag)), + Left_Opnd => New_Node, Right_Opnd => Make_Integer_Literal (Loc, Type_Access_Level (PtrT))), Reason => PE_Accessibility_Check_Failed)); @@ -2594,6 +2607,8 @@ Clen : Node_Id; Set : Boolean; + -- Start of processing for Expand_Concatenate + begin -- Choose an appropriate computational type Index: exp_ch6.adb =================================================================== --- exp_ch6.adb (revision 177351) +++ exp_ch6.adb (working copy) @@ -5382,21 +5382,6 @@ -- Start of processing for Expand_N_Subprogram_Body begin - -- If this is the main compilation unit, and we are generating code for - -- VM targets, we now generate the Type Specific Data record of all the - -- enclosing tagged type declarations. - - -- If the runtime package Ada_Tags has not been loaded then this - -- subprogram does not have tagged type declarations and there is no - -- need to search for tagged types to generate their TSDs. - - if not Tagged_Type_Expansion - and then Unit (Cunit (Main_Unit)) = N - and then RTU_Loaded (Ada_Tags) - then - Build_VM_TSDs (N); - end if; - -- Set L to either the list of declarations if present, or to the list -- of statements if no declarations are present. This is used to insert -- new stuff at the start. Index: exp_disp.adb =================================================================== --- exp_disp.adb (revision 177378) +++ exp_disp.adb (working copy) @@ -61,6 +61,7 @@ with Stand; use Stand; with Stringt; use Stringt; with SCIL_LL; use SCIL_LL; +with Targparm; use Targparm; with Tbuild; use Tbuild; with Uintp; use Uintp; @@ -82,10 +83,6 @@ -- 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 Make_VM_TSD (Typ : Entity_Id) return List_Id; - -- Build the Type Specific Data record associated with tagged type Typ. - -- Invoked only when generating code for VM targets. - 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 @@ -298,6 +295,7 @@ return Static_Dispatch_Tables and then Is_Library_Level_Tagged_Type (Typ) + and then VM_Target = No_VM -- If the type is derived from a CPP class we cannot statically -- build the dispatch tables because we must inherit primitives @@ -468,156 +466,6 @@ end if; end Build_Static_Dispatch_Tables; - ------------------- - -- Build_VM_TSDs -- - ------------------- - - procedure Build_VM_TSDs (N : Entity_Id) is - Target_List : List_Id := No_List; - - procedure Build_TSDs (List : List_Id); - -- Build the static dispatch table of tagged types found in the list of - -- declarations. Add the generated nodes to the end of Target_List. - - procedure Build_Package_TSDs (N : Node_Id); - -- Build static dispatch tables associated with package declaration N - - --------------------------- - -- Build_Dispatch_Tables -- - --------------------------- - - procedure Build_TSDs (List : List_Id) is - D : Node_Id; - - begin - D := First (List); - while Present (D) loop - - -- Handle nested packages and package bodies recursively. The - -- generated code is placed on the Target_List established for - -- the enclosing compilation unit. - - if Nkind (D) = N_Package_Declaration then - Build_Package_TSDs (D); - - elsif Nkind_In (D, N_Package_Body, - N_Subprogram_Body) - then - Build_TSDs (Declarations (D)); - - elsif Nkind (D) = N_Package_Body_Stub - and then Present (Library_Unit (D)) - then - Build_TSDs - (Declarations (Proper_Body (Unit (Library_Unit (D))))); - - -- Handle full type declarations and derivations of library - -- level tagged types - - elsif Nkind_In (D, N_Full_Type_Declaration, - N_Derived_Type_Definition) - and then Ekind (Defining_Entity (D)) /= E_Record_Subtype - and then Is_Tagged_Type (Defining_Entity (D)) - and then not Is_Private_Type (Defining_Entity (D)) - then - -- Do not generate TSDs for the internal types created for - -- a type extension with unknown discriminants. The needed - -- information is shared with the source type. - -- See Expand_N_Record_Extension. - - if Is_Underlying_Record_View (Defining_Entity (D)) - or else - (not Comes_From_Source (Defining_Entity (D)) - and then - Has_Unknown_Discriminants (Etype (Defining_Entity (D))) - and then - not Comes_From_Source - (First_Subtype (Defining_Entity (D)))) - then - null; - - else - if No (Target_List) then - Target_List := New_List; - end if; - - Append_List_To (Target_List, - Make_VM_TSD (Defining_Entity (D))); - end if; - end if; - - Next (D); - end loop; - end Build_TSDs; - - ------------------------ - -- Build_Package_TSDs -- - ------------------------ - - procedure Build_Package_TSDs (N : Node_Id) is - Spec : constant Node_Id := Specification (N); - Vis_Decls : constant List_Id := Visible_Declarations (Spec); - Priv_Decls : constant List_Id := Private_Declarations (Spec); - - begin - if Present (Priv_Decls) then - Build_TSDs (Vis_Decls); - Build_TSDs (Priv_Decls); - - elsif Present (Vis_Decls) then - Build_TSDs (Vis_Decls); - end if; - end Build_Package_TSDs; - - -- Start of processing for Build_VM_TSDs - - begin - if not Expander_Active - or else No_Run_Time_Mode - or else Tagged_Type_Expansion - or else not RTE_Available (RE_Type_Specific_Data) - then - return; - end if; - - if Nkind (N) = N_Package_Declaration then - declare - Spec : constant Node_Id := Specification (N); - Vis_Decls : constant List_Id := Visible_Declarations (Spec); - Priv_Decls : constant List_Id := Private_Declarations (Spec); - - begin - Build_Package_TSDs (N); - - if Present (Target_List) then - Analyze_List (Target_List); - - if Present (Priv_Decls) - and then Is_Non_Empty_List (Priv_Decls) - then - Append_List (Target_List, Priv_Decls); - else - Append_List (Target_List, Vis_Decls); - end if; - end if; - end; - - elsif Nkind_In (N, N_Package_Body, N_Subprogram_Body) then - if Is_Non_Empty_List (Declarations (N)) then - Build_TSDs (Declarations (N)); - - if Nkind (N) = N_Subprogram_Body then - Build_TSDs (Statements (Handled_Statement_Sequence (N))); - end if; - - if Present (Target_List) then - Analyze_List (Target_List); - Append_List (Target_List, Declarations (N)); - end if; - end if; - end if; - end Build_VM_TSDs; - ------------------------------ -- Convert_Tag_To_Interface -- ------------------------------ @@ -1278,11 +1126,37 @@ and then Is_Interface (Iface_Typ))); if not Tagged_Type_Expansion then + if VM_Target /= No_VM then + if Is_Access_Type (Operand_Typ) then + Operand_Typ := Designated_Type (Operand_Typ); + end if; - -- For VM, just do a conversion ??? + if Is_Class_Wide_Type (Operand_Typ) then + Operand_Typ := Root_Type (Operand_Typ); + end if; - Rewrite (N, Unchecked_Convert_To (Etype (N), N)); - Analyze (N); + if not Is_Static + and then Operand_Typ /= Iface_Typ + then + Insert_Action (N, + Make_Procedure_Call_Statement (Loc, + Name => New_Occurrence_Of + (RTE (RE_Check_Interface_Conversion), Loc), + Parameter_Associations => New_List ( + Make_Attribute_Reference (Loc, + Prefix => Duplicate_Subexpr (Expression (N)), + Attribute_Name => Name_Tag), + Make_Attribute_Reference (Loc, + Prefix => New_Reference_To (Iface_Typ, Loc), + Attribute_Name => Name_Tag)))); + end if; + + -- Just do a conversion ??? + + Rewrite (N, Unchecked_Convert_To (Etype (N), N)); + Analyze (N); + end if; + return; end if; @@ -6764,13 +6638,20 @@ -- Check_TSD -- (TSD => TSD'Unrestricted_Access); - Append_To (Result, - Make_Procedure_Call_Statement (Loc, - Name => New_Reference_To (RTE (RE_Check_TSD), Loc), - Parameter_Associations => New_List ( - Make_Attribute_Reference (Loc, - Prefix => New_Reference_To (TSD, Loc), - Attribute_Name => Name_Unrestricted_Access)))); + if Ada_Version >= Ada_2005 + and then Is_Library_Level_Entity (Typ) + and then Has_External_Tag_Rep_Clause (Typ) + and then RTE_Available (RE_Check_TSD) + and then not Debug_Flag_QQ + then + Append_To (Result, + Make_Procedure_Call_Statement (Loc, + Name => New_Reference_To (RTE (RE_Check_TSD), Loc), + Parameter_Associations => New_List ( + Make_Attribute_Reference (Loc, + Prefix => New_Reference_To (TSD, Loc), + Attribute_Name => Name_Unrestricted_Access)))); + end if; -- Generate: -- Register_TSD (TSD'Unrestricted_Access); @@ -7653,6 +7534,7 @@ begin pragma Assert (not Restriction_Active (No_Dispatching_Calls)); + pragma Assert (VM_Target = No_VM); -- Do not register in the dispatch table eliminated primitives Index: exp_disp.ads =================================================================== --- exp_disp.ads (revision 177274) +++ exp_disp.ads (working copy) @@ -6,7 +6,7 @@ -- -- -- S p e c -- -- -- --- 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- -- @@ -186,11 +186,6 @@ -- bodies they are added to the end of the list of declarations of the -- package body. - procedure Build_VM_TSDs (N : Entity_Id); - -- N is a library level package declaration, a library level package body - -- or a library level subprogram body. Build the runtime Type Specific - -- Data record of all the tagged types declared inside N. - function Convert_Tag_To_Interface (Typ : Entity_Id; Expr : Node_Id) return Node_Id; pragma Inline (Convert_Tag_To_Interface); @@ -353,6 +348,10 @@ -- tagged types this routine imports the forward declaration of the tag -- entity, that will be declared and exported by Make_DT. + function Make_VM_TSD (Typ : Entity_Id) return List_Id; + -- Build the Type Specific Data record associated with tagged type Typ. + -- Invoked only when generating code for VM targets. + function Register_Primitive (Loc : Source_Ptr; Prim : Entity_Id) return List_Id; Index: sem_disp.adb =================================================================== --- sem_disp.adb (revision 177320) +++ sem_disp.adb (working copy) @@ -49,6 +49,7 @@ with Sem_Util; use Sem_Util; with Snames; use Snames; with Sinfo; use Sinfo; +with Targparm; use Targparm; with Tbuild; use Tbuild; with Uintp; use Uintp; @@ -1028,6 +1029,12 @@ " the type!", Subp); end if; + -- No code required to register primitives in VM + -- targets + + elsif VM_Target /= No_VM then + null; + else Insert_Actions_After (Subp_Body, Register_Primitive (Sloc (Subp_Body), @@ -1158,10 +1165,13 @@ while Present (Elmt) loop Prim := Node (Elmt); + -- No code required to register primitives in VM targets + if Present (Alias (Prim)) and then Present (Interface_Alias (Prim)) and then Alias (Prim) = Subp and then not Building_Static_DT (Tagged_Type) + and then VM_Target = No_VM then Insert_Actions_After (Subp_Body, Register_Primitive (Sloc (Subp_Body), Prim => Prim)); Index: exp_ch3.adb =================================================================== --- exp_ch3.adb (revision 177328) +++ exp_ch3.adb (working copy) @@ -5022,27 +5022,6 @@ Set_Homonym (Defining_Identifier (N), Homonym (Def_Id)); Exchange_Entities (Defining_Identifier (N), Def_Id); end; - - -- Handle initialization of class-wide interface object in VM - -- targets - - elsif not Tagged_Type_Expansion then - - -- Replace - -- CW : I'Class := Obj; - -- by - -- CW : I'Class; - -- CW := I'Class (Obj); [1] - - -- The assignment [1] is later expanded in a dispatching - -- call to _assign - - Set_Expression (N, Empty); - - Insert_Action (N, - Make_Assignment_Statement (Loc, - Name => New_Reference_To (Def_Id, Loc), - Expression => Convert_To (Typ, Relocate_Node (Expr)))); end if; return; @@ -6170,6 +6149,9 @@ if not Building_Static_DT (Def_Id) then Append_Freeze_Actions (Def_Id, Make_DT (Def_Id)); end if; + + elsif VM_Target /= No_VM then + Append_Freeze_Actions (Def_Id, Make_VM_TSD (Def_Id)); end if; -- If the type has unknown discriminants, propagate dispatching