diff mbox

[Ada] Uniform trees for certain aspects and corresponding source pragmas

Message ID 20140120155202.GA25437@adacore.com
State New
Headers show

Commit Message

Arnaud Charlet Jan. 20, 2014, 3:52 p.m. UTC
This patch ensures that the sole argument of pragmas Abstract_State,
Contract_Cases, Depends, Global, Initializes, Refined_Depends, Refined_Global
and Refined_State is always an aggregate unless it is "null". The end result of
this change is a uniform tree in both aspect specifications and pragmas. This
change is intended for the formal verification tools.

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

--  uniform_tree.adb

procedure Uniform_Tree is
   G : Integer := 0;

   procedure Test_01 (X : out Integer) is
      pragma Global (In_Out => G);
   begin
      X := G;
   end Test_01;

   procedure Test_02 (X : out Integer)
     with Global => (In_Out => G)
   is
   begin
      X := G;
   end Test_02;
begin
   null;
end Uniform_Tree;

----------------------------
-- Compilation and output --
----------------------------

$ gcc -c -gnatd.V -gnatdg uniform_tree.adb
procedure uniform_tree is
   g : integer := 0;

   procedure uniform_tree__test_01 (x : out integer) is
      pragma global ((
         in_out => g));
   begin
      x := g;
      return;
   end uniform_tree__test_01;

   procedure uniform_tree__test_02 (x : out integer) is
      pragma global ((
         in_out => g));
   begin
      x := g;
      return;
   end uniform_tree__test_02
     with global => (
             in_out => g);
begin
   null;
   return;
end uniform_tree;

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

2014-01-20  Hristian Kirtchev  <kirtchev@adacore.com>

	* sem_prag.adb (Analyze_Pragma): Ensure that
	the sole argument of pragmas Abstract_State, Contract_Cases,
	Depends, Global and Initializes in in aggregate form.
	(Analyze_Refined_Pragma): Ensure that the sole argument of
	pragmas Refined_Depends, Refined_Global and Refined_State is in
	aggregate form.
	(Ensure_Aggregate_Form): New routine.
diff mbox

Patch

Index: sem_prag.adb
===================================================================
--- sem_prag.adb	(revision 206835)
+++ sem_prag.adb	(working copy)
@@ -1,4 +1,4 @@ 
------------------------------------------------------------------------------
+------------------------------------------------------------------------------
 --                                                                          --
 --                         GNAT COMPILER COMPONENTS                         --
 --                                                                          --
@@ -449,39 +449,38 @@ 
       Subp_Id   := Defining_Entity (Subp_Decl);
       All_Cases := Get_Pragma_Arg (First (Pragma_Argument_Associations (N)));
 
-      --  Multiple contract cases appear in aggregate form
+      --  Single and multiple contract cases must appear in aggregate form. If
+      --  this is not the case, then either the parser of the analysis of the
+      --  pragma failed to produce an aggregate.
 
-      if Nkind (All_Cases) = N_Aggregate then
-         if No (Component_Associations (All_Cases)) then
-            Error_Msg_N ("wrong syntax for aspect Contract_Cases", N);
+      pragma Assert (Nkind (All_Cases) = N_Aggregate);
 
-         --  Individual contract cases appear as component associations
+      if No (Component_Associations (All_Cases)) then
+         Error_Msg_N ("wrong syntax for aspect Contract_Cases", N);
 
-         else
-            --  Ensure that the formal parameters are visible when analyzing
-            --  all clauses. This falls out of the general rule of aspects
-            --  pertaining to subprogram declarations. Skip the installation
-            --  for subprogram bodies because the formals are already visible.
+      --  Individual contract cases appear as component associations
 
-            if not In_Open_Scopes (Subp_Id) then
-               Restore_Scope := True;
-               Push_Scope (Subp_Id);
-               Install_Formals (Subp_Id);
-            end if;
+      else
+         --  Ensure that the formal parameters are visible when analyzing all
+         --  clauses. This falls out of the general rule of aspects pertaining
+         --  to subprogram declarations. Skip the installation for subprogram
+         --  bodies because the formals are already visible.
 
-            CCase := First (Component_Associations (All_Cases));
-            while Present (CCase) loop
-               Analyze_Contract_Case (CCase);
-               Next (CCase);
-            end loop;
+         if not In_Open_Scopes (Subp_Id) then
+            Restore_Scope := True;
+            Push_Scope (Subp_Id);
+            Install_Formals (Subp_Id);
+         end if;
 
-            if Restore_Scope then
-               End_Scope;
-            end if;
+         CCase := First (Component_Associations (All_Cases));
+         while Present (CCase) loop
+            Analyze_Contract_Case (CCase);
+            Next (CCase);
+         end loop;
+
+         if Restore_Scope then
+            End_Scope;
          end if;
-
-      else
-         Error_Msg_N ("wrong syntax for aspect Contract_Cases", N);
       end if;
    end Analyze_Contract_Cases_In_Decl_Part;
 
@@ -2577,32 +2576,26 @@ 
 
       Collect_States_And_Variables;
 
-      --  Multiple initialization clauses appear as an aggregate
+      --  Single and multiple initialization clauses must appear as an
+      --  aggregate. If this is not the case, then either the parser of
+      --  the analysis of the pragma failed to produce an aggregate.
 
-      if Nkind (Inits) = N_Aggregate then
-         if Present (Expressions (Inits)) then
-            Init := First (Expressions (Inits));
-            while Present (Init) loop
-               Analyze_Initialization_Item (Init);
+      pragma Assert (Nkind (Inits) = N_Aggregate);
 
-               Next (Init);
-            end loop;
-         end if;
+      if Present (Expressions (Inits)) then
+         Init := First (Expressions (Inits));
+         while Present (Init) loop
+            Analyze_Initialization_Item (Init);
+            Next (Init);
+         end loop;
+      end if;
 
-         if Present (Component_Associations (Inits)) then
-            Init := First (Component_Associations (Inits));
-            while Present (Init) loop
-               Analyze_Initialization_Item_With_Inputs (Init);
-
-               Next (Init);
-            end loop;
-         end if;
-
-      --  Various forms of a single initialization clause. Note that these may
-      --  include malformed initializations.
-
-      else
-         Analyze_Initialization_Item (Inits);
+      if Present (Component_Associations (Inits)) then
+         Init := First (Component_Associations (Inits));
+         while Present (Init) loop
+            Analyze_Initialization_Item_With_Inputs (Init);
+            Next (Init);
+         end loop;
       end if;
    end Analyze_Initializes_In_Decl_Part;
 
@@ -2620,8 +2613,8 @@ 
       --  name may be different from the pragma name.
 
       Pragma_Exit : exception;
-      --  This exception is used to exit pragma processing completely. It is
-      --  used when an error is detected, and no further processing is
+      --  This exception is used to exit pragma processing completely. It
+      --  is used when an error is detected, and no further processing is
       --  required. It is also used if an earlier error has left the tree in
       --  a state where the pragma should not be processed.
 
@@ -2656,8 +2649,8 @@ 
       --  Subsidiary routine to the analysis of body pragmas Refined_Depends,
       --  Refined_Global and Refined_Post. Check the placement and related
       --  context of the pragma. Spec_Id is the entity of the related
-      --  subprogram. Body_Id is the entity of the subprogram body. Flag Legal
-      --  is set when the pragma is properly placed.
+      --  subprogram. Body_Id is the entity of the subprogram body. Flag
+      --  Legal is set when the pragma is properly placed.
 
       procedure Check_Ada_83_Warning;
       --  Issues a warning message for the current pragma if operating in Ada
@@ -2910,6 +2903,12 @@ 
       --  presence of at least one component. UU_Typ is the related Unchecked_
       --  Union type.
 
+      procedure Ensure_Aggregate_Form (Arg : Node_Id);
+      --  Subsidiary routine to the processing of pragmas Abstract_State,
+      --  Contract_Cases, Depends, Global, Initializes, Refined_Depends,
+      --  Refined_Global and Refined_State. Transform argument Arg into an
+      --  aggregate if not one already. N_Null is never transformed.
+
       procedure Error_Pragma (Msg : String);
       pragma No_Return (Error_Pragma);
       --  Outputs error message for current pragma. The message contains a %
@@ -2936,15 +2935,15 @@ 
 
       procedure Error_Pragma_Arg_Ident (Msg : String; Arg : Node_Id);
       pragma No_Return (Error_Pragma_Arg_Ident);
-      --  Outputs error message for current pragma. The message may contain
-      --  a % that will be replaced with the pragma name. The parameter Arg
-      --  must be a pragma argument association with a non-empty identifier
-      --  (i.e. its Chars field must be set), and the error message is placed
-      --  on the identifier. The message is placed using Error_Msg_N so
-      --  the message may also contain an & insertion character which will
-      --  reference the identifier. After placing the message, Pragma_Exit
-      --  is raised. Note: this routine calls Fix_Error (see spec of that
-      --  procedure for details).
+      --  Outputs error message for current pragma. The message may contain a %
+      --  that will be replaced with the pragma name. The parameter Arg must be
+      --  a pragma argument association with a non-empty identifier (i.e. its
+      --  Chars field must be set), and the error message is placed on the
+      --  identifier. The message is placed using Error_Msg_N so the message
+      --  may also contain an & insertion character which will reference
+      --  the identifier. After placing the message, Pragma_Exit is raised.
+      --  Note: this routine calls Fix_Error (see spec of that procedure for
+      --  details).
 
       procedure Error_Pragma_Ref (Msg : String; Ref : Entity_Id);
       pragma No_Return (Error_Pragma_Ref);
@@ -3221,6 +3220,13 @@ 
          Check_Arg_Count (1);
          Check_No_Identifiers;
 
+         if Nam_In (Pname, Name_Refined_Depends,
+                           Name_Refined_Global,
+                           Name_Refined_State)
+         then
+            Ensure_Aggregate_Form (Arg1);
+         end if;
+
          --  Verify the placement of the pragma and check for duplicates. The
          --  pragma must apply to a subprogram body [stub].
 
@@ -5110,6 +5116,70 @@ 
          end loop;
       end Check_Variant;
 
+      ---------------------------
+      -- Ensure_Aggregate_Form --
+      ---------------------------
+
+      procedure Ensure_Aggregate_Form (Arg : Node_Id) is
+         Expr  : constant Node_Id    := Get_Pragma_Arg (Arg);
+         Loc   : constant Source_Ptr := Sloc (Arg);
+         Nam   : constant Name_Id    := Chars (Arg);
+         Comps : List_Id := No_List;
+         Exprs : List_Id := No_List;
+
+      begin
+         --  The argument is already in aggregate form, but the presence of a
+         --  name causes this to be interpreted as a named association which in
+         --  turn must be converted into an aggregate.
+
+         --    pragma Global (In_Out => (A, B, C))
+         --                   ^         ^
+         --                   name      aggregate
+
+         --    pragma Global ((In_Out => (A, B, C)))
+         --                   ^          ^
+         --                   aggregate  aggregate
+
+         if Nkind (Expr) = N_Aggregate then
+            if Nam = No_Name then
+               return;
+            end if;
+
+         --  Do not transform a null argument into an aggregate as N_Null has
+         --  special meaning in formal verification pragmas.
+
+         elsif Nkind (Expr) = N_Null then
+            return;
+         end if;
+
+         --  Positional argument is transformed into an aggregate with an
+         --  Expressions list.
+
+         if Nam = No_Name then
+            Exprs := New_List (Relocate_Node (Expr));
+
+         --  An associative argument is transformed into an aggregate with
+         --  Component_Associations.
+
+         else
+            Comps := New_List (
+              Make_Component_Association (Loc,
+                Choices    => New_List (Make_Identifier (Loc, Chars (Arg))),
+                Expression => Relocate_Node (Expr)));
+
+         end if;
+
+         --  Remove the pragma argument name as this information has been
+         --  captured in the aggregate.
+
+         Set_Chars (Arg, No_Name);
+
+         Set_Expression (Arg,
+           Make_Aggregate (Loc,
+             Component_Associations => Comps,
+             Expressions            => Exprs));
+      end Ensure_Aggregate_Form;
+
       ------------------
       -- Error_Pragma --
       ------------------
@@ -9654,6 +9724,7 @@ 
             GNAT_Pragma;
             S14_Pragma;
             Check_Arg_Count (1);
+            Ensure_Aggregate_Form (Arg1);
 
             --  Ensure the proper placement of the pragma. Abstract states must
             --  be associated with a package declaration.
@@ -9677,7 +9748,7 @@ 
 
             State := Expression (Arg1);
 
-            --  Multiple abstract states appear as an aggregate
+            --  Multiple non-null abstract states appear as an aggregate
 
             if Nkind (State) = N_Aggregate then
                State := First (Expressions (State));
@@ -11305,6 +11376,7 @@ 
          begin
             GNAT_Pragma;
             Check_Arg_Count (1);
+            Ensure_Aggregate_Form (Arg1);
 
             --  The pragma is analyzed at the end of the declarative part which
             --  contains the related subprogram. Reset the analyzed flag.
@@ -11824,6 +11896,7 @@ 
             GNAT_Pragma;
             S14_Pragma;
             Check_Arg_Count (1);
+            Ensure_Aggregate_Form (Arg1);
 
             --  Ensure the proper placement of the pragma. Depends must be
             --  associated with a subprogram declaration or a body that acts
@@ -13094,6 +13167,7 @@ 
             GNAT_Pragma;
             S14_Pragma;
             Check_Arg_Count (1);
+            Ensure_Aggregate_Form (Arg1);
 
             --  Ensure the proper placement of the pragma. Global must be
             --  associated with a subprogram declaration or a body that acts
@@ -13937,6 +14011,7 @@ 
             GNAT_Pragma;
             S14_Pragma;
             Check_Arg_Count (1);
+            Ensure_Aggregate_Form (Arg1);
 
             --  Ensure the proper placement of the pragma. Initializes must be
             --  associated with a package declaration.
@@ -22116,7 +22191,7 @@ 
       Abstr_States := New_Copy_Elist (Abstract_States (Spec_Id));
       Collect_Hidden_States;
 
-      --  Multiple state refinements appear as an aggregate
+      --  Multiple non-null state refinements appear as an aggregate
 
       if Nkind (Clauses) = N_Aggregate then
          if Present (Expressions (Clauses)) then