This patch allows classwide postconditions on null procedures when the aspect expression includes calls to abstract functions that must be rewrittne as dispatching calls.
The following must compile and execute quietly: gnatmake -gnat12 -gnata -q test_class test_class -- with objects; use Objects; with objects.child; use Objects.child; with objects.child.grand; use Objects.child.grand; procedure test_class is Thing : Objects.child.O2; Thing2 : O2; Thing3 : O3; procedure Dispatch (It : in out Object'class) is begin P1 (It); end; procedure D2 (It : in out O2'class) is begin P2 (It); end; begin Dispatch (Thing); D2 (Thing2); D2 (Thing3); P2 (Object (Thing)); end; -- package Objects is type Object is interface; procedure P1 (This : in out Object) is abstract with Post'Class => This.Get_X'Old = This.Get_X; procedure P2 (This : in out Object) is null with Post'Class => This.Get_X'Old = This.Get_X; function Get_X (This : Object) return Float is abstract; end Objects; --- package Objects.Child is type O2 is new object with private; overriding procedure P1 (This : in out O2) ; overriding function Get_X (This : O2) return Float; overriding procedure P2 (This : in out O2) -- is null with Post'class => (this.Check > 1.0); function Check (This : O2) return Float; private type O2 is new Object with record Value : Float := 3.14; end record; end Objects.Child; --- package body Objects.Child is procedure P1 (This : in out O2) is begin null; end; function Get_X (This : O2) return Float is begin return This.Value; end; procedure P2 (This : in out O2) is begin null; end; function Check (This : O2) return Float is begin return This.Value; end; end Objects.Child; --- package Objects.Child.Grand is type O3 is new O2 with private; function Check (This : O3) return Float; private type O3 is new O2 with record Counter : Integer := 123; end record; end Objects.Child.Grand; --- package body Objects.Child.Grand is function Check (This : O3) return Float is begin return This.Value + Float (This.Counter); end; end Objects.Child.Grand; Tested on x86_64-pc-linux-gnu, committed on trunk 2013-04-11 Ed Schonberg <schonb...@adacore.com> * sem_disp.adb (Check_Dispatching_Context): If the context is a contract for a null procedure defer error reporting until postcondition body is created. * exp_ch13.adb (Expand_N_Freeze_Entity): If the entity is a null procedure, complete the analysis of its contracts so that calls within classwide conditions are properly rewritten as dispatching calls.
Index: exp_ch13.adb =================================================================== --- exp_ch13.adb (revision 197743) +++ exp_ch13.adb (working copy) @@ -6,7 +6,7 @@ -- -- -- B o d y -- -- -- --- Copyright (C) 1992-2012, Free Software Foundation, Inc. -- +-- Copyright (C) 1992-2013, 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- -- @@ -43,6 +43,7 @@ with Sem_Ch7; use Sem_Ch7; with Sem_Ch8; use Sem_Ch8; with Sem_Eval; use Sem_Eval; +with Sem_Prag; use Sem_Prag; with Sem_Util; use Sem_Util; with Sinfo; use Sinfo; with Snames; use Snames; @@ -553,6 +554,28 @@ end; else + -- If the action is the generated body of a null subprogram, + -- analyze the expressions in its delayed aspects, because we + -- may not have reached the end of the declarative list when + -- delayed aspects are normally analyzed. This ensures that + -- dispatching calls are properly rewritten when the inner + -- postcondition procedure is analyzed. + + if Is_Subprogram (E) + and then Nkind (Parent (E)) = N_Procedure_Specification + and then Null_Present (Parent (E)) + then + declare + Prag : Node_Id; + begin + Prag := Spec_PPC_List (Contract (E)); + while Present (Prag) loop + Analyze_PPC_In_Decl_Part (Prag, E); + Prag := Next_Pragma (Prag); + end loop; + end; + end if; + Analyze (Decl, Suppress => All_Checks); end if; Index: sem_disp.adb =================================================================== --- sem_disp.adb (revision 197786) +++ sem_disp.adb (working copy) @@ -536,6 +536,21 @@ Set_Entity (Name (N), Alias (Subp)); return; + -- An obscure special case: a null procedure may have a class- + -- wide pre/postcondition that includes a call to an abstract + -- subp. Calls within the expression may not have been rewritten + -- as dispatching calls yet, because the null body appears in + -- the current declarative part. The expression will be properly + -- rewritten/reanalyzed when the postcondition procedure is built. + + elsif In_Spec_Expression + and then Is_Subprogram (Current_Scope) + and then + Nkind (Parent (Current_Scope)) = N_Procedure_Specification + and then Null_Present (Parent (Current_Scope)) + then + null; + else -- We need to determine whether the context of the call -- provides a tag to make the call dispatching. This requires