OSDN Git Service

gcc/ada/
authorsam <sam@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 14 May 2008 07:07:24 +0000 (07:07 +0000)
committersam <sam@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 14 May 2008 07:07:24 +0000 (07:07 +0000)
* sem_attr.adb (Analyze_Attribute, Attribute_Old case): Add
restrictions to the prefix of 'Old.
* sem_util.ads, sem_util.adb (In_Parameter_Specification): New.
* gnat_rm.texi ('Old): Note that 'Old cannot be applied to local
variables.

    gcc/testsuite/
* gnat.dg/old_errors.ads, gnat.dg/old_errors.adb: New.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@135282 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ada/ChangeLog
gcc/ada/gnat_rm.texi
gcc/ada/sem_attr.adb
gcc/ada/sem_util.adb
gcc/ada/sem_util.ads
gcc/testsuite/ChangeLog
gcc/testsuite/gnat.dg/old_errors.adb [new file with mode: 0644]
gcc/testsuite/gnat.dg/old_errors.ads [new file with mode: 0644]

index cffae3b..b473b8e 100644 (file)
@@ -1,3 +1,12 @@
+2008-05-14  Samuel Tardieu  <sam@rfc1149.net>
+            Robert Dewar <dewar@adacore.com>
+
+       * sem_attr.adb (Analyze_Attribute, Attribute_Old case): Add
+       restrictions to the prefix of 'Old.
+       * sem_util.ads, sem_util.adb (In_Parameter_Specification): New.
+       * gnat_rm.texi ('Old): Note that 'Old cannot be applied to local
+       variables.
+
 2008-05-13  Eric Botcazou  <ebotcazou@adacore.com>
 
        PR ada/24880
index f8d5939..c048581 100644 (file)
@@ -5774,7 +5774,8 @@ you can refer to Arg1.Field'Old which yields the value of
 Arg1.Field on entry. The implementation simply involves generating
 an object declaration which captures the value on entry. Any
 prefix is allowed except one of a limited type (since limited
-types cannot be copied to capture their values).
+types cannot be copied to capture their values) or a local variable
+(since it does not exist at subprogram entry time).
 
 The following example shows the use of 'Old to implement
 a test of a postcondition:
index 7550d90..6a7846e 100644 (file)
@@ -3480,6 +3480,68 @@ package body Sem_Attr is
             Error_Attr ("attribute % cannot apply to limited objects", P);
          end if;
 
+         --  Check that the expression does not refer to local entities
+
+         Check_Local : declare
+            Subp : Entity_Id := Current_Subprogram;
+
+            function Process (N : Node_Id) return Traverse_Result;
+            --  Check that N does not contain references to local variables
+            --  or other local entities of Subp.
+
+            -------------
+            -- Process --
+            -------------
+
+            function Process (N : Node_Id) return Traverse_Result is
+            begin
+               if Is_Entity_Name (N)
+                 and then not Is_Formal (Entity (N))
+                 and then Enclosing_Subprogram (Entity (N)) = Subp
+               then
+                  Error_Msg_Node_1 := Entity (N);
+                  Error_Attr
+                    ("attribute % cannot refer to local variable&", N);
+               end if;
+
+               return OK;
+            end Process;
+
+            procedure Check_No_Local is new Traverse_Proc;
+
+         --  Start of processing for Check_Local
+
+         begin
+            Check_No_Local (P);
+
+            if In_Parameter_Specification (P) then
+
+               --  We have additional restrictions on using 'Old in parameter
+               --  specifications.
+
+               if Present (Enclosing_Subprogram (Current_Subprogram)) then
+
+                  --  Check that there is no reference to the enclosing
+                  --  subprogram local variables. Otherwise, we might end
+                  --  up being called from the enclosing subprogram and thus
+                  --  using 'Old on a local variable which is not defined
+                  --  at entry time.
+
+                  Subp := Enclosing_Subprogram (Current_Subprogram);
+                  Check_No_Local (P);
+
+               else
+                  --  We must prevent default expression of library-level
+                  --  subprogram from using 'Old, as the subprogram may be
+                  --  used in elaboration code for which there is no enclosing
+                  --  subprogram.
+
+                  Error_Attr
+                    ("attribute % can only appear within subprogram", N);
+               end if;
+            end if;
+         end Check_Local;
+
       ------------
       -- Output --
       ------------
index 1be22cf..c335417 100644 (file)
@@ -5374,6 +5374,26 @@ package body Sem_Util is
       return False;
    end In_Package_Body;
 
+   --------------------------------
+   -- In_Parameter_Specification --
+   --------------------------------
+
+   function In_Parameter_Specification (N : Node_Id) return Boolean is
+      PN : Node_Id;
+
+   begin
+      PN := Parent (N);
+      while Present (PN) loop
+         if Nkind (PN) = N_Parameter_Specification then
+            return True;
+         end if;
+
+         PN := Parent (PN);
+      end loop;
+
+      return False;
+   end In_Parameter_Specification;
+
    --------------------------------------
    -- In_Subprogram_Or_Concurrent_Unit --
    --------------------------------------
index a14d6a0..866bd7f 100644 (file)
@@ -590,6 +590,9 @@ package Sem_Util is
    function In_Package_Body return Boolean;
    --  Returns True if current scope is within a package body
 
+   function In_Parameter_Specification (N : Node_Id) return Boolean;
+   --  Returns True if node N belongs to a parameter specification
+
    function In_Subprogram_Or_Concurrent_Unit return Boolean;
    --  Determines if the current scope is within a subprogram compilation
    --  unit (inside a subprogram declaration, subprogram body, or generic
index ff7b73d..05a2d25 100644 (file)
@@ -1,3 +1,7 @@
+2008-05-14  Samuel Tardieu  <sam@rfc1149.net>
+
+       * gnat.dg/old_errors.ads, gnat.dg/old_errors.adb: New.
+
 2008-05-14  Andreas Krebbel  <krebbel1@de.ibm.com>
 
        * g++.dg/eh/080513-1.C: New testcase.
diff --git a/gcc/testsuite/gnat.dg/old_errors.adb b/gcc/testsuite/gnat.dg/old_errors.adb
new file mode 100644 (file)
index 0000000..846c6c6
--- /dev/null
@@ -0,0 +1,47 @@
+-- { dg-do compile }
+package body Old_Errors is
+
+   A : Integer;
+
+   function F
+     (X : Integer := A'Old) -- { dg-error "can only appear within subprogram" }
+     return Integer is
+   begin
+      return X;
+   end F;
+
+   procedure P (I : in Integer; O : out Integer; IO : in out Integer) is
+      Y : Integer := 0;
+      function G
+        (X : Integer := Y'Old) -- { dg-error "cannot refer to local variable" }
+        return Integer is
+      begin
+         return X;
+      end G;
+
+      function H (X : Integer := A'Old) return Integer is  -- OK
+      begin
+         return X;
+      end H;
+
+   begin
+      Y := Y'Old; -- { dg-error "cannot refer to local variable" }
+      declare
+         Z : Integer := 0;
+         procedure Inner is
+            IL : Integer := 0;
+         begin
+            IL := IL'Old; -- { dg-error "cannot refer to local variable" }
+            Z  := Z'Old;  -- OK
+         end Inner;
+      begin
+         Y := Z'Old; -- { dg-error "cannot refer to local variable" }
+      end;
+      Y := I'Old;   -- OK
+      Y := O'Old;   -- OK
+      Y := IO'Old;  -- OK
+      Y := G;       -- OK, error has been signalled at G declaration
+      pragma Assert (G (3)'Old = Y); -- { dg-error "cannot refer to local variable" }
+   end P;
+
+end Old_Errors;
diff --git a/gcc/testsuite/gnat.dg/old_errors.ads b/gcc/testsuite/gnat.dg/old_errors.ads
new file mode 100644 (file)
index 0000000..84717ff
--- /dev/null
@@ -0,0 +1,5 @@
+package Old_Errors is
+
+   pragma Elaborate_Body;
+
+end Old_Errors;