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 <dismu...@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).
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;