diff mbox

[Ada] Constants without variable input are not hidden state

Message ID 20150522101145.GA16635@adacore.com
State New
Headers show

Commit Message

Arnaud Charlet May 22, 2015, 10:11 a.m. UTC
This patch implements the following rule with respect to constants:

   SPARK RM 7.1.1(2) - The hidden state of a package P consists of:
   * any variables, or constants with variable inputs, declared immediately in
   the private part or body of P.

Constants without variable input are not considered part of the hidden state of
a package. These constants do not require indicator Part_Of when declared in
the private part of a package.

------------
-- Source --
------------

--  types.ads

ackage Types is
   type CA is array (1 .. 3) of Integer;
   type UA is array (Integer range <>) of Integer;

   type VR (Discr : Boolean) is record
      Comp_1 : Integer;

      case Discr is
         when True =>
            Comp_2 : Integer;
         when others =>
            null;
      end case;
   end record;

   subtype CR is VR (True);

   function Get_CA return CA;
   function Get_CR return CR;
   function Get_In return Integer;
   function Get_UA return UA;
   function Get_VR return VR;
end Types;

--  types.adb

package body Types is
   function Get_CA return CA is
      Result : constant CA := (others => 0);
   begin
      return Result;
   end Get_CA;

   function Get_CR return CR is
      Result : constant CR := (Discr => True, Comp_1 => 0, Comp_2 => 0);
   begin
      return Result;
   end Get_CR;

   function Get_In return Integer is
   begin
      return 0;
   end Get_In;

   function Get_UA return UA is
   begin
      return (0, 0, 0);
   end Get_UA;

   function Get_VR return VR is
   begin
      return (Discr => False, Comp_1 => 0);
   end Get_VR;
end Types;

--  legal_hidden_state.ads

with Types; use Types;
pragma Elaborate_All (Types);

package Legal_Hidden_State
  with SPARK_Mode,
       Abstract_State => State
is
   procedure Force_Body;

private
   --  Constrained array

   C1 : constant CA := Get_CA with Part_Of => State;
   C2 : constant CA := (others => Get_In) with Part_Of => State;
   C3 : constant CA := (1, 2, Get_In) with Part_Of => State;

   --  Constrained record

   C4 : constant CR := Get_CR with Part_Of => State;
   C5 : constant CR :=
          (Discr => True, Comp_1 => 1, Comp_2 => Get_In) with Part_Of => State;

   --  Scalar

   C6 : constant Integer := Get_In with Part_Of => State;

   --  Unconstrained array

   C7 : constant UA := Get_UA with Part_Of => State;
   C8 : constant UA (1 .. 3) := (others => Get_In) with Part_Of => State;
   C9 : constant UA := (1, 2, Get_In) with Part_Of => State;

   --  Variant record

   C10 : constant VR := Get_VR with Part_Of => State;
   C11 : constant VR :=
           (Discr => False, Comp_1 => Get_In) with Part_Of => State;
   C12 : constant VR (False) :=
           (Discr => False, Comp_1 => Get_In) with Part_Of => State;
end Legal_Hidden_State;

--  legal_hidden_state.adb

package body Legal_Hidden_State
  with SPARK_Mode,
       Refined_State =>
         (State =>
           (C1,  C2,  C3,  C4,  C5,  C6,  C7,  C8,  C9,  C10, C11, C12,
            C13, C14, C15, C16, C17, C18, C19, C20, C21, C22, C23, C24))
is
   --  Constrained array

   C13 : constant CA := Get_CA;
   C14 : constant CA := (others => Get_In);
   C15 : constant CA := (1, 2, Get_In);

   --  Constrained record

   C16 : constant CR := Get_CR;
   C17 : constant CR := (Discr => True, Comp_1 => 17, Comp_2 => Get_In);

   --  Scalar

   C18 : constant Integer := Get_In;

   --  Unconstrained array

   C19 : constant UA := Get_UA;
   C20 : constant UA (1 .. 3) := (others => Get_In);
   C21 : constant UA := (1, 2, Get_In);

   --  Variant record

   C22 : constant VR := Get_VR;
   C23 : constant VR := (Discr => False, Comp_1 => Get_In);
   C24 : constant VR (False) := (Discr => False, Comp_1 => Get_In);

   procedure Force_Body is begin null; end Force_Body;
end Legal_Hidden_State;

-----------------
-- Compilation --
-----------------

$ gcc -c legal_hidden_state.adb

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

2015-05-22  Hristian Kirtchev  <kirtchev@adacore.com>

	* sem_prag.adb (Analyze_Pragma): Constants without variable
	input do not require indicator Part_Of.
	(Check_Missing_Part_Of): Constants without variable input do not
	requrie indicator Part_Of.
	(Collect_Visible_States): Constants without variable input are
	not part of the hidden state of a package.
	* sem_util.ads, sem_util.adb (Has_Variable_Input): New routine.
diff mbox

Patch

Index: sem_prag.adb
===================================================================
--- sem_prag.adb	(revision 223484)
+++ sem_prag.adb	(working copy)
@@ -2710,7 +2710,7 @@ 
          Legal   : out Boolean);
       --  Subsidiary to the analysis of pragmas Abstract_State and Part_Of.
       --  Perform full analysis of indicator Part_Of. Item_Id is the entity of
-      --  an abstract state, variable or package instantiation. State is the
+      --  an abstract state, object or package instantiation. State is the
       --  encapsulating state. Indic is the Part_Of indicator. Flag Legal is
       --  set when the indicator is legal.
 
@@ -17557,6 +17557,20 @@ 
                Legal   => Legal);
 
             if Legal then
+
+               --  Constants without "variable input" are not considered part
+               --  of the hidden state of a package (SPARK RM 7.1.1(2)). As a
+               --  result such constants do not require a Part_Of indicator.
+
+               if Ekind (Item_Id) = E_Constant
+                 and then not Has_Variable_Input (Item_Id)
+               then
+                  SPARK_Msg_NE
+                    ("useless Part_Of indicator, constant & does not have "
+                     & "variable input", N, Item_Id);
+                  return;
+               end if;
+
                State_Id := Entity (State);
 
                --  The Part_Of indicator turns an object into a constituent of
@@ -24448,7 +24462,18 @@ 
                   --  formals to their actuals as the formals cannot be named
                   --  from the outside and participate in refinement.
 
-                  if No (Corresponding_Generic_Association (Decl)) then
+                  if Present (Corresponding_Generic_Association (Decl)) then
+                     null;
+
+                  --  Constants without "variable input" are not considered a
+                  --  hidden state of a package (SPARK RM 7.1.1(2)).
+
+                  elsif Ekind (Item_Id) = E_Constant
+                    and then not Has_Variable_Input (Item_Id)
+                  then
+                     null;
+
+                  else
                      Add_Item (Item_Id, Result);
                   end if;
 
@@ -24993,6 +25018,14 @@ 
 
       elsif SPARK_Mode /= On then
          return;
+
+      --  Do not consider constants without variable input because those are
+      --  not part of the hidden state of a package (SPARK RM 7.1.1(2)).
+
+      elsif Ekind (Item_Id) = E_Constant
+        and then not Has_Variable_Input (Item_Id)
+      then
+         return;
       end if;
 
       --  Find where the abstract state, variable or package instantiation
Index: sem_util.adb
===================================================================
--- sem_util.adb	(revision 223484)
+++ sem_util.adb	(working copy)
@@ -9317,6 +9317,18 @@ 
       end if;
    end Has_Tagged_Component;
 
+   ------------------------
+   -- Has_Variable_Input --
+   ------------------------
+
+   function Has_Variable_Input (Const_Id : Entity_Id) return Boolean is
+      Expr : constant Node_Id := Expression (Declaration_Node (Const_Id));
+
+   begin
+      return
+        Present (Expr) and then not Compile_Time_Known_Value_Or_Aggr (Expr);
+   end Has_Variable_Input;
+
    ----------------------------
    -- Has_Volatile_Component --
    ----------------------------
Index: sem_util.ads
===================================================================
--- sem_util.ads	(revision 223484)
+++ sem_util.ads	(working copy)
@@ -1046,6 +1046,11 @@ 
    --  component is present. This function is used to check if "=" has to be
    --  expanded into a bunch component comparisons.
 
+   function Has_Variable_Input (Const_Id : Entity_Id) return Boolean;
+   --  Determine whether the initialization expression of constant Const_Id has
+   --  "variable input" (SPARK RM 7.1.1(2)). This roughly maps to the semantic
+   --  concept of a compile-time known value.
+
    function Has_Volatile_Component (Typ : Entity_Id) return Boolean;
    --  Given an arbitrary type, determine whether it contains at least one
    --  volatile component.