Patchwork [Ada] Wrong conformance checking for null exclusions of dispatching ops

login
register
mail settings
Submitter Arnaud Charlet
Date Aug. 2, 2011, 3 p.m.
Message ID <20110802150037.GA16474@adacore.com>
Download mbox | patch
Permalink /patch/107940/
State New
Headers show

Comments

Arnaud Charlet - Aug. 2, 2011, 3 p.m.
The compiler improperly checks subtype conformance of null exclusions on
anonymous access parameters in Ada 2005 cases involving dispatching operations.
In Ada 2005, controlling access parameters are defined to implicitly exclude
null (more properly, their anonymous access type excludes null). The test for
null exclusion conformance improperly tested the null exclusion of the formals
themselves rather than their type, but the Can_Never_Be_Null attribute is only
set consistently for access formals in Ada 95 mode. The fix is to test null
exclusion of the anonymous access types rather than the formals. This addresses
two problems: 1) a dispatching operation with access parameters declared in
an Ada 2005 unit that overrides a subprogram inherited from an Ada 95 unit
no longer has to use "not null" on its controlling access parameters, and
2) applying 'Access to a dispatching operation with controlling access formals
properly requires the corresponding formal in the expected access-to-subprogram
type to have an explicit null exclusion.


The first test case must compile quietly:

$ gcc -c nnull_incomp_b.ads

pragma Ada_95;
package NNull_Incomp_A is
   type My_Type is abstract tagged null record;
   procedure P (T : access My_Type) is abstract;
end;

pragma Ada_2005; --  This compiles if I use Ada_95 instead
with NNull_Incomp_A; use NNull_Incomp_A;
package NNull_Incomp_B is
   type My_Derived_Type is abstract new
     NNull_Incomp_A.My_Type with null record;
   procedure P (T : access My_Derived_Type) is abstract;
end;

The second test case must give the following error output when compiled with:
$ gcc -c -gnat05 acc_to_subp_conformance_bug.adb

     1. procedure Acc_To_Subp_Conformance_Bug is
     2.
     3.    package Pkg is
     4.
     5.       type TT is tagged null record;
     6.
     7.       type Acc_TT_Proc_with_null is access procedure (X : access TT);
     8.
     9.       type Acc_TT_Proc_not_null is access procedure (X : not null access TT);
    10.
    11.       procedure Proc (X : access TT);
    12.
    13.    end Pkg;
    14.
    15.    package body Pkg is
    16.
    17.       procedure Proc (X : access TT) is
    18.       begin
    19.          null;
    20.       end Proc;
    21.
    22.    end Pkg;
    23.
    24.    use Pkg;
    25.
    26.    A1 : Acc_TT_Proc_with_null := Proc'Access;  -- ERROR (but GNAT doesn't flag)
                                         |
        >>> not subtype conformant with declaration at line 7
        >>> type of "X" does not match

    27.    A2 : Acc_TT_Proc_not_null  := Proc'Access;  -- OK (but GNAT flags an error)
    28.
    29. begin
    30.    null;
    31. end Acc_To_Subp_Conformance_Bug;

 31 lines: 2 errors


procedure Acc_To_Subp_Conformance_Bug is

   package Pkg is

      type TT is tagged null record;

      type Acc_TT_Proc_with_null is access procedure (X : access TT);

      type Acc_TT_Proc_not_null is access procedure (X : not null access TT);

      procedure Proc (X : access TT);

   end Pkg;

   package body Pkg is

      procedure Proc (X : access TT) is
      begin
         null;
      end Proc;

   end Pkg;

   use Pkg;

   A1 : Acc_TT_Proc_with_null := Proc'Access;  -- ERROR (but GNAT doesn't flag)
   A2 : Acc_TT_Proc_not_null  := Proc'Access;  -- OK (but GNAT flags an error)

begin
   null;
end Acc_To_Subp_Conformance_Bug;

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

2011-08-02  Gary Dismukes  <dismukes@adacore.com>

	* sem_ch6.adb (Check_Conformance): Revise the check for nonconforming
	null exclusions to test Can_Never_Be_Null on the anonymous access types
	of the formals rather than testing the formals themselves. Exclude this
	check in cases where the Old_Formal is marked as a controlling formal,
	to avoid issuing spurious errors for bodies completing dispatching
	operations (due to the flag not getting set on controlling access
	formals in body specs).
	(Find_Corresponding_Spec): When checking full and subtype conformance of
	subprogram bodies in instances, pass Designated and E in that order, for
	consistency with the expected order of the formals (New_Id followed by
	Old_Id).

Patch

Index: sem_ch6.adb
===================================================================
--- sem_ch6.adb	(revision 177156)
+++ sem_ch6.adb	(working copy)
@@ -6,7 +6,7 @@ 
 --                                                                          --
 --                                 B o d y                                  --
 --                                                                          --
---          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- --
@@ -4144,14 +4144,21 @@ 
 
             --  Ada 2005 (AI-231): In case of anonymous access types check
             --  the null-exclusion and access-to-constant attributes must
-            --  match.
+            --  match. For null exclusion, we test the types rather than the
+            --  formals themselves, since the attribute is only set reliably
+            --  on the formals in the Ada 95 case, and we exclude the case
+            --  where Old_Formal is marked as controlling, to avoid errors
+            --  when matching completing bodies with dispatching declarations
+            --  (access formals in the bodies aren't marked Can_Never_Be_Null).
 
             if Ada_Version >= Ada_2005
               and then Ekind (Etype (Old_Formal)) = E_Anonymous_Access_Type
               and then Ekind (Etype (New_Formal)) = E_Anonymous_Access_Type
               and then
-                (Can_Never_Be_Null (Old_Formal) /=
-                 Can_Never_Be_Null (New_Formal)
+                ((Can_Never_Be_Null (Etype (Old_Formal)) /=
+                  Can_Never_Be_Null (Etype (New_Formal))
+                    and then
+                      not Is_Controlling_Formal (Old_Formal))
                    or else
                  Is_Access_Constant (Etype (Old_Formal)) /=
                  Is_Access_Constant (Etype (New_Formal)))
@@ -6250,11 +6257,11 @@ 
 
                   if Nkind (N) = N_Subprogram_Body
                     and then Present (Homonym (E))
-                    and then not Fully_Conformant (E, Designator)
+                    and then not Fully_Conformant (Designator, E)
                   then
                      goto Next_Entity;
 
-                  elsif not Subtype_Conformant (E, Designator) then
+                  elsif not Subtype_Conformant (Designator, E) then
                      goto Next_Entity;
                   end if;
                end if;