Patchwork [Ada] Pre/Postconditions on generic subprograms

login
register
mail settings
Submitter Arnaud Charlet
Date Aug. 2, 2011, 2:03 p.m.
Message ID <20110802140302.GA27515@adacore.com>
Download mbox | patch
Permalink /patch/107925/
State New
Headers show

Comments

Arnaud Charlet - Aug. 2, 2011, 2:03 p.m.
This patch is a partial implementation of pre/postconditions that apply to
generic subprograms and are inherited by the corresponding instantiations.
This implementation does not defer the analysis of the corresponding aspects
to a later point, and therefore is restricted to conditions that only depend
on the formals and the generic formals of the unit.

The following must compile and execute quietly:

    gnatmake -gnat12 -gnata try_list
    try_list

---
with T; use T;
procedure Try_List is
   Short_List : Lists.List;
   function Inc (X : integer) return integer is
   begin
      return  X + 1;
   end Inc;
   procedure Map_Inc is new Map_F (Inc);
begin
   Short_List.Append (15);
   Map_Inc (Short_List);
end;
---
with Ada.Containers.Doubly_Linked_Lists;
package T is
   package Lists is new Ada.Containers.Doubly_Linked_Lists (Integer);
   use Lists;

   generic
      with function F (E : Integer) return Integer;
   procedure Map_F (L : in out List) with
     Pre => (for all Cu in L => Element (Cu) /= F (Element (Cu)));
end T;
---
package body T is
   procedure Map_F (L : in out List) is
      Current : Cursor := First (L);
   begin
      while Current /= No_Element loop
         Replace_Element (L, Current, F (Element (Current)));
         Next (Current);
      end loop;
   end Map_F;
end T;

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

2011-08-02  Ed Schonberg  <schonberg@adacore.com>

	* sem_ch12.adb (Analyze_Generic_Subprogram_Declaration): copy properly
	the aspect declarations and attach them to the generic copy for
	subsequent analysis.
	(Analyze_Subprogram_Instantiation): copy explicitly the aspect
	declarations of the generic tree to the new subprogram declarations.
	* sem_attr.adb (Check_Precondition_Postcondition): recognize
	conditions that apply to a subprogram instance.

Patch

Index: sem_prag.adb
===================================================================
--- sem_prag.adb	(revision 177147)
+++ sem_prag.adb	(working copy)
@@ -1738,8 +1738,19 @@ 
             --  Skip stuff not coming from source
 
             elsif not Comes_From_Source (PO) then
-               null;
 
+               --  The condition may apply to a subprogram instantiation.
+
+               if Nkind (PO) = N_Subprogram_Declaration
+                 and then Present (Generic_Parent (Specification (PO)))
+               then
+                  Chain_PPC (PO);
+                  return;
+
+               else
+                  null;
+               end if;
+
             --  Only remaining possibility is subprogram declaration
 
             else
@@ -7554,6 +7565,7 @@ 
                   then
                      Set_Elaborate_Present (Citem, True);
                      Set_Unit_Name (Get_Pragma_Arg (Arg), Name (Citem));
+                     Generate_Reference (Entity (Name (Citem)), Citem);
 
                      --  With the pragma present, elaboration calls on
                      --  subprograms from the named unit need no further
Index: sem_ch12.adb
===================================================================
--- sem_ch12.adb	(revision 177144)
+++ sem_ch12.adb	(working copy)
@@ -2794,6 +2794,20 @@ 
       Set_Parent_Spec (New_N, Save_Parent);
       Rewrite (N, New_N);
 
+      --  The aspect specifications are not attached to the tree, and must
+      --  be copied and attached to the generic copy explicitly.
+
+      if Present (Aspect_Specifications (New_N)) then
+         declare
+            Aspects : constant List_Id := Aspect_Specifications (N);
+         begin
+            Set_Has_Aspects (N, False);
+            Move_Aspects (New_N, N);
+            Set_Has_Aspects (Original_Node (N), False);
+            Set_Aspect_Specifications (Original_Node (N), Aspects);
+         end;
+      end if;
+
       Spec := Specification (N);
       Id := Defining_Entity (Spec);
       Generate_Definition (Id);
@@ -2888,16 +2902,42 @@ 
 
       Save_Global_References (Original_Node (N));
 
+      --  To capture global references, analyze the expressions of aspects,
+      --  and propagate information to original tree. Note that in this case
+      --  analysis of attributes is not delayed until the freeze point.
+      --  It seems very hard to recreate the proper visibility of the generic
+      --  subprogram at a later point because the analysis of an aspect may
+      --  create pragmas after the generic copies have been made ???
+
+      if Has_Aspects (N) then
+         declare
+            Aspect : Node_Id;
+
+         begin
+            Aspect := First (Aspect_Specifications (N));
+            while Present (Aspect) loop
+               if Get_Aspect_Id (Chars (Identifier (Aspect)))
+                  /= Aspect_Warnings
+               then
+                  Analyze (Expression (Aspect));
+               end if;
+               Next (Aspect);
+            end loop;
+
+            Aspect := First (Aspect_Specifications (Original_Node (N)));
+            while Present (Aspect) loop
+               Save_Global_References (Expression (Aspect));
+               Next (Aspect);
+            end loop;
+         end;
+      end if;
+
       End_Generic;
       End_Scope;
       Exit_Generic_Scope (Id);
       Generate_Reference_To_Formals (Id);
 
       List_Inherited_Pre_Post_Aspects (Id);
-
-      if Has_Aspects (N) then
-         Analyze_Aspect_Specifications (N, Id);
-      end if;
    end Analyze_Generic_Subprogram_Declaration;
 
    -----------------------------------
@@ -4262,6 +4302,12 @@ 
            Make_Subprogram_Declaration (Sloc (Act_Spec),
              Specification => Act_Spec);
 
+         --  The aspects have been copied previously, but they have to be
+         --  linked explicitly to the new subprogram declaration.
+         --  Explicit pre/postconditions on the instance are analyzed below,
+         --  in a separate step.
+
+         Move_Aspects (Act_Tree, Act_Decl);
          Set_Categorization_From_Pragmas (Act_Decl);
 
          if Parent_Installed then