[Ada] Interface type conversions are not dynamically tagged

Message ID 20110905141227.GA17140@adacore.com
State New
Headers show

Commit Message

Arnaud Charlet Sept. 5, 2011, 2:12 p.m.
A view conversion to an interface type is expanded into a dereference of a
temporary that involves the class-wide interface type. Nevertheless such an
expression is not dynamically tagged, and is not a controlling argument in 
a call.

Compiling main.adb must be rejected with:

   main.adb:8:10: call to abstract procedure must be dispatching

with Types; use Types;
procedure Main is
    V : R;
    I (V).P1;
    I'Class (V).P1;
    I (V).P2;
    I'Class (V).P2;
end Main;
package Types  is
  type I is interface;

   procedure P1 (V : I)  is null;
   procedure P2 (V : I) is abstract;

   type R is new I with null record;

   procedure P2 (V : R) is null;
end Types;

Tested on x86_64-pc-linux-gnu, committed on trunk

2011-09-05  Ed Schonberg  <schonberg@adacore.com>

	* sem_disp.adb (Find_Controlling_Arg): Add checks for
	interface type conversions, that are expanded into dereferences.


Index: sem_disp.adb
--- sem_disp.adb	(revision 178381)
+++ sem_disp.adb	(working copy)
@@ -1616,6 +1616,32 @@ 
          return Controlling_Argument (Orig_Node);
+      --  Type conversions are dynamically tagged if the target type, or its
+      --  designated type, are classwide. An interface conversion expands into
+      --  a dereference, so test must be performed on the original node.
+      elsif Nkind (Orig_Node) = N_Type_Conversion
+        and then Nkind (N) = N_Explicit_Dereference
+        and then Is_Controlling_Actual (N)
+      then
+         declare
+            Target_Type : constant Entity_Id :=
+                             Entity (Subtype_Mark (Orig_Node));
+         begin
+            if Is_Class_Wide_Type (Target_Type) then
+               return N;
+            elsif Is_Access_Type (Target_Type)
+              and then Is_Class_Wide_Type (Designated_Type (Target_Type))
+            then
+               return N;
+            else
+               return Empty;
+            end if;
+         end;
       --  Normal case
       elsif Is_Controlling_Actual (N)