sem_attr.adb (Analyze_Attribute, [...]): Add restrictions to the prefix of 'Old.
authorSamuel Tardieu <sam@rfc1149.net>
Wed, 14 May 2008 07:07:24 +0000 (07:07 +0000)
committerSamuel Tardieu <sam@gcc.gnu.org>
Wed, 14 May 2008 07:07:24 +0000 (07:07 +0000)
    gcc/ada/
* 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.

Co-Authored-By: Robert Dewar <dewar@adacore.com>
From-SVN: r135282

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 cffae3bc3a71c5ceaf2cd4898489a038a6ba387d..b473b8e6fc21800c9c861ca106003a7e56e744ea 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 f8d5939b70889e00fcc78c6480f37def2f575a69..c048581d662d2e801fd35d7dfeb0c3c807a1c42b 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 7550d90655d933d90ba8994bd5dd547168c35faf..6a7846eacba6befd861e407b741dd03282738c51 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 1be22cf7df0ec4c234d4c2d716c065a0e32fa396..c335417d1b705e7a234b198936c294c14a290a93 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 a14d6a0149fe49e80a2d86f5f6c9756a954f42b1..866bd7f98a569ec0585f38806d599a501aa270b8 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 ff7b73d74df277b0451f331a7f88e6cc53ea708b..05a2d2569a00e27d1fbce628fb3c0002df205871 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;