This patch fixes a regression in the handling of the generic_dispatching_ constructor in the presence of several levels of interfaces. Previous to this patch, a dispatching call might call the wrong primitive of an object whose type overrides a primitive inherited from an interface that has several ancestors, if the object is built through a call to an instance of the generic_dispatching constructor.
Executing: gnatmake -q main main must yield Output Input Output Input --- with Ada.Streams.Stream_IO; use Ada.Streams.Stream_IO; with Ada.Streams; use Ada.Streams; with Ada.Tags; use Ada.Tags; with Messages; use Messages; procedure Main is procedure WriteAndRead (obj : access IOutput'Class) is file : File_Type; pStream : Stream_Access; begin Create (file, Name => "buffer"); pStream := Stream (file); String'Output (pStream, External_Tag (obj'Tag)); obj.Output (pStream); Close (file); Open (file, Mode => In_File, Name => "buffer"); pStream := Stream (file); declare obj : IInput'Class := ClassInput (Internal_Tag (String'Input (pStream)), pStream); begin null; end; Close (file); end WriteAndRead; begin WriteAndRead (new CTest_Success); WriteAndRead (new CTest_Fail); end Main; --- with Ada.Streams; with Ada.Tags.Generic_Dispatching_Constructor; package Messages is type CMessage is tagged null record; type IBase is interface; procedure Nothing (X : Ibase) is abstract; type IInput is interface and IBase; function Input (stream : not null access Ada.Streams.Root_Stream_Type'Class) return IInput is abstract; overriding procedure Nothing (X : IInput) is null; type IOutput is interface and IBase; procedure Output (self : in IOutput; stream : not null access Ada.Streams.Root_Stream_Type'Class) is abstract; overriding procedure Nothing (X : IOutput) is null; type IInputOutput is interface and IInput and IOutput; function ClassInput is new Ada.Tags.Generic_Dispatching_Constructor (IInput, Ada.Streams.Root_Stream_Type'Class, Input); ------------------------------ -- correct procedure called -- ------------------------------ type CTest_Success is new CMessage and IInput and IOutput with record dummyInt : Integer := 123; end record; overriding function Input (stream : not null access Ada.Streams.Root_Stream_Type'Class) return CTest_Success; overriding procedure Output (self : in CTest_Success; stream : not null access Ada.Streams.Root_Stream_Type'Class); ---------------------------- -- wrong procedure called -- ---------------------------- type CTest_Fail is new CMessage and IInputOutput with record dummyInt : Integer := 456; end record; overriding function Input (stream : not null access Ada.Streams.Root_Stream_Type'Class) return CTest_Fail; overriding procedure Output (self : in CTest_Fail; stream : not null access Ada.Streams.Root_Stream_Type'Class); end Messages; -- with Ada.Text_IO; package body Messages is overriding function Input (stream : not null access Ada.Streams.Root_Stream_Type'Class) return CTest_Success is begin Ada.Text_IO.Put_Line ("Input"); return CTest_Success'(dummyInt => Integer'Input (stream)); end Input; overriding procedure Output (self : in CTest_Success; stream : not null access Ada.Streams.Root_Stream_Type'Class) is begin Ada.Text_IO.Put_Line ("Output"); Integer'Output (stream, self.dummyInt); end Output; overriding function Input (stream : not null access Ada.Streams.Root_Stream_Type'Class) return CTest_Fail is begin Ada.Text_IO.Put_Line ("Input"); return CTest_Fail'(dummyInt => Integer'Input (Stream)); end Input; overriding procedure Output (self : in CTest_Fail; stream : not null access Ada.Streams.Root_Stream_Type'Class) is begin Ada.Text_IO.Put_Line ("Output"); Integer'Output (stream, self.dummyInt); end Output; end Messages; Tested on x86_64-pc-linux-gnu, committed on trunk 2015-05-12 Ed Schonberg <schonb...@adacore.com> * exp_intr.adb (Expand_Dispatching_Constructor_Call): The tag to be retrieved for the generated call is the first entry in the dispatch table for the return type of the instantiated constructor.
Index: exp_intr.adb =================================================================== --- exp_intr.adb (revision 223033) +++ exp_intr.adb (working copy) @@ -345,6 +345,9 @@ begin pragma Assert (not Is_Interface (Etype (Tag_Arg))); + -- The tag is the first entry in the dispatch table of the + -- return type of the constructor. + Iface_Tag := Make_Object_Declaration (Loc, Defining_Identifier => Make_Temporary (Loc, 'V'), @@ -357,7 +360,7 @@ Relocate_Node (Tag_Arg), New_Occurrence_Of (Node (First_Elmt (Access_Disp_Table - (Etype (Etype (Act_Constr))))), + (Etype (Act_Constr)))), Loc)))); Insert_Action (N, Iface_Tag); end;