When the frontend resolves a dispatching call through the object
operation notation it must also check if there is a class-wide
subprogram covering the target primitive. This check was missing
in the frontend. After this patch the following test must
compile with errors:

package Pkg1 is
   type Iface is interface;
   procedure Yet_Another_Op (Obj : in out Iface'Class);
end;

with Pkg1;
package Pkg2 is
   type Typ is new Pkg1.Iface with null record;

   procedure Yet_Another_Op (Obj : in out Typ);
end;

with Pkg1; use Pkg1;
with Pkg2; use Pkg2;
procedure Main is
   T : Pkg2.Typ;
begin
   T.Yet_Another_Op;  -- Ambiguous? (Yes)
end;

Command: gcc -c -gnat05 main.adb
Output:
main.adb:7:05: ambiguous expression (cannot resolve "Yet_Another_Op")
main.adb:7:05: possible interpretation at pkg2.ads:6
main.adb:7:05: possible interpretation at pkg1.ads:3

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

2011-08-31  Javier Miranda  <mira...@adacore.com>

        * sem_ch4.adb (Try_Object_Operation): When a dispatching primitive is
        found check if there is a class-wide subprogram covering the primitive.
        
Index: sem_ch4.adb
===================================================================
--- sem_ch4.adb (revision 178360)
+++ sem_ch4.adb (working copy)
@@ -6638,7 +6638,7 @@
          Call    : Node_Id;
          Subp    : Entity_Id) return Entity_Id;
       --  If the subprogram is a valid interpretation, record it, and add
-      --  to the list of interpretations of Subprog.
+      --  to the list of interpretations of Subprog. Otherwise return Empty.
 
       procedure Complete_Object_Operation
         (Call_Node       : Node_Id;
@@ -7104,6 +7104,14 @@
                     and then N = Name (Parent (N))
                   then
                      goto Next_Hom;
+
+                  --  If the context is a function call, ignore procedures
+                  --  in the name of the call.
+
+                  elsif Ekind (Hom) = E_Procedure
+                    and then Nkind (Parent (N)) /= N_Procedure_Call_Statement
+                  then
+                     goto Next_Hom;
                   end if;
 
                   Set_Etype (Call_Node, Any_Type);
@@ -7271,16 +7279,39 @@
             return;
          end if;
 
-         if Try_Primitive_Operation
-              (Call_Node       => New_Call_Node,
-               Node_To_Replace => Node_To_Replace)
-           or else
-             Try_Class_Wide_Operation
-               (Call_Node       => New_Call_Node,
-                Node_To_Replace => Node_To_Replace)
-         then
-            null;
-         end if;
+         declare
+            Dup_Call_Node : constant Node_Id := New_Copy (New_Call_Node);
+            CW_Result     : Boolean;
+            Prim_Result   : Boolean;
+            pragma Unreferenced (CW_Result);
+
+         begin
+            Prim_Result :=
+              Try_Primitive_Operation
+                (Call_Node       => New_Call_Node,
+                 Node_To_Replace => Node_To_Replace);
+
+            --  Check if there is a class-wide subprogram covering the
+            --  primitive. This check must be done even if a candidate
+            --  was found in order to report ambiguous calls.
+
+            if not (Prim_Result) then
+               CW_Result :=
+                 Try_Class_Wide_Operation
+                   (Call_Node       => New_Call_Node,
+                    Node_To_Replace => Node_To_Replace);
+
+            --  If we found a primitive we search for class-wide subprograms
+            --  using a duplicate of the call node (done to avoid missing its
+            --  decoration if there is no ambiguity).
+
+            else
+               CW_Result :=
+                 Try_Class_Wide_Operation
+                   (Call_Node       => Dup_Call_Node,
+                    Node_To_Replace => Node_To_Replace);
+            end if;
+         end;
       end Try_One_Prefix_Interpretation;
 
       -----------------------------

Reply via email to