]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
exp_util.adb (Get_Current_Value_Condition, [...]): Handle the case of expressions...
authorThomas Quinot <quinot@adacore.com>
Thu, 17 Oct 2013 13:58:39 +0000 (13:58 +0000)
committerArnaud Charlet <charlet@gcc.gnu.org>
Thu, 17 Oct 2013 13:58:39 +0000 (15:58 +0200)
2013-10-17  Thomas Quinot  <quinot@adacore.com>

* exp_util.adb (Get_Current_Value_Condition,
Set_Current_Value_Condition): Handle the case of expressions
with actions * exp_util.adb (Insert_Actions): Handle the case
of an expression with actions whose Actions list is empty.
* exp_util.adb (Remove_Side_Effects.Side_Effect_Free): An
expression with actions that has no Actions and whose Expression
is side effect free is itself side effect free.
* exp_util.adb (Remove_Side_Effects): Do not set an incorrect etype on
temporary 'R' (Def_Id), which is in general an access to Exp_Type, not
an Exp_Type.
* sem_res.adb (Resolve): For an expression with
actions, resolve the expression early. * sem_res.adb
(Resolve_Expression_With_Actions): Rewrite an expression with
actions whose value is compile time known and which has no
actions into just its expression, so that its constant value is
available downstream.
* sem_res.adb (Resolve_Short_Circuit):
Wrap the left operand in an expression with actions to contain
any required finalization actions.
* exp_ch4.adb (Expand_Expression_With_Actions): For an
expression with actions returning a Boolean expression, ensure
any finalization action is kept within the Actions list.
* sem_warn.adb (Check_References, Check_Unset_Reference): add
missing circuitry to handle expressions with actions.
* checks.adb (Ensure_Valid): For an expression with actions,
insert the validity check on the Expression.
* sem_ch13.adb (Build_Static_Predicate.Get_RList): An expression
with actions that has a non-empty Actions list is not static. An
expression with actions that has an empty Actions list has the
static ranges of its Expression.
* sem_util.adb (Has_No_Obvious_Side_Effects): An expression with
actions with an empty Actions list has no obvious side effects
if its Expression itsekf has no obvious side effects.

From-SVN: r203763

gcc/ada/ChangeLog
gcc/ada/checks.adb
gcc/ada/exp_ch4.adb
gcc/ada/exp_util.adb
gcc/ada/sem_ch13.adb
gcc/ada/sem_res.adb
gcc/ada/sem_util.adb
gcc/ada/sem_warn.adb

index 0580bf2d97293903df1ea38172138dcef481b000..a815f366bc63f91d4db2b51471b83dda9c201055 100644 (file)
@@ -1,3 +1,39 @@
+2013-10-17  Thomas Quinot  <quinot@adacore.com>
+
+       * exp_util.adb (Get_Current_Value_Condition,
+       Set_Current_Value_Condition): Handle the case of expressions
+       with actions * exp_util.adb (Insert_Actions): Handle the case
+       of an expression with actions whose Actions list is empty.
+       * exp_util.adb (Remove_Side_Effects.Side_Effect_Free): An
+       expression with actions that has no Actions and whose Expression
+       is side effect free is itself side effect free.
+       * exp_util.adb (Remove_Side_Effects): Do not set an incorrect etype on
+       temporary 'R' (Def_Id), which is in general an access to Exp_Type, not
+       an Exp_Type.
+       * sem_res.adb (Resolve): For an expression with
+       actions, resolve the expression early.  * sem_res.adb
+       (Resolve_Expression_With_Actions): Rewrite an expression with
+       actions whose value is compile time known and which has no
+       actions into just its expression, so that its constant value is
+       available downstream.
+       * sem_res.adb (Resolve_Short_Circuit):
+       Wrap the left operand in an expression with actions to contain
+       any required finalization actions.
+       * exp_ch4.adb (Expand_Expression_With_Actions): For an
+       expression with actions returning a Boolean expression, ensure
+       any finalization action is kept within the Actions list.
+       * sem_warn.adb (Check_References, Check_Unset_Reference): add
+       missing circuitry to handle expressions with actions.
+       * checks.adb (Ensure_Valid): For an expression with actions,
+       insert the validity check on the Expression.
+       * sem_ch13.adb (Build_Static_Predicate.Get_RList): An expression
+       with actions that has a non-empty Actions list is not static. An
+       expression with actions that has an empty Actions list has the
+       static ranges of its Expression.
+       * sem_util.adb (Has_No_Obvious_Side_Effects): An expression with
+       actions with an empty Actions list has no obvious side effects
+       if its Expression itsekf has no obvious side effects.
+
 2013-10-17  Ed Schonberg  <schonberg@adacore.com>
 
        * sem_aux.ads, sem_aux.adb (Is_Immutably_Limited_Type): Make
index 65dedc20a95aaf4597f7bc9c6f6ab02112b8edbb..328e05e5aaf30db70b05525c23b8f706f46fa52c 100644 (file)
@@ -5092,6 +5092,13 @@ package body Checks is
       then
          return;
 
+      --  For an expression with actions, we want to insert the validity check
+      --  on the final Expression.
+
+      elsif Nkind (Expr) = N_Expression_With_Actions then
+         Ensure_Valid (Expression (Expr));
+         return;
+
       --  An annoying special case. If this is an out parameter of a scalar
       --  type, then the value is not going to be accessed, therefore it is
       --  inappropriate to do any validity check at the call site.
index 00da14726b1cdd9cafb37f819851d4d1eb9e0d0d..0356b67e6c69fc85b789db9605aaa63007c802cc 100644 (file)
@@ -12135,15 +12135,26 @@ package body Exp_Ch4 is
      (Decl     : Node_Id;
       Rel_Node : Node_Id)
    is
-      function Find_Enclosing_Context (N : Node_Id) return Node_Id;
-      --  Find the logical context where N appears. The context is chosen such
-      --  that it is possible to insert before and after it.
+      Hook_Context         : Node_Id;
+      --  Node on which to insert the hook pointer (as an action)
 
-      ----------------------------
-      -- Find_Enclosing_Context --
-      ----------------------------
+      Finalization_Context : Node_Id;
+      --  Node after which to insert finalization actions
+
+      Finalize_Always : Boolean;
+      --  If False, call to finalizer includes a test of whether the
+      --  hook pointer is null.
 
-      function Find_Enclosing_Context (N : Node_Id) return Node_Id is
+      procedure Find_Enclosing_Contexts (N : Node_Id);
+      --  Find the logical context where N appears, and initializae
+      --  Hook_Context and Finalization_Context accordingly. Also
+      --  sets Finalize_Always.
+
+      -----------------------------
+      -- Find_Enclosing_Contexts --
+      -----------------------------
+
+      procedure Find_Enclosing_Contexts (N : Node_Id) is
          Par : Node_Id;
          Top : Node_Id;
 
@@ -12153,7 +12164,7 @@ package body Exp_Ch4 is
          --  other controlled values can reuse it.
 
          if Scope_Is_Transient then
-            return Node_To_Be_Wrapped;
+            Hook_Context := Node_To_Be_Wrapped;
 
          --  In some cases, such as return statements, no transient scope is
          --  generated, in which case we have to look up in the tree to find
@@ -12193,7 +12204,8 @@ package body Exp_Ch4 is
                                              N_Parameter_Association,
                                              N_Pragma_Argument_Association)
                then
-                  return Par;
+                  Hook_Context := Par;
+                  goto Hook_Context_Found;
 
                --  Prevent the search from going too far
 
@@ -12204,26 +12216,10 @@ package body Exp_Ch4 is
                Par := Parent (Par);
             end loop;
 
-            return Par;
-
-         --  Short circuit operators in complex expressions are converted into
-         --  expression_with_actions.
+            Hook_Context := Par;
+            goto Hook_Context_Found;
 
          else
-            --  Handle the case where the node is buried deep inside an if
-            --  statement. The temporary controlled object must be finalized
-            --  before the then, elsif or else statements are evaluated.
-
-            --    if Something
-            --      and then Ctrl_Func_Call
-            --    then
-            --       <result must be finalized at this point>
-            --       <statements>
-            --    end if;
-
-            --  To achieve this, find the topmost logical operator. Generated
-            --  actions are then inserted before/after it.
-
             Par := N;
             while Present (Par) loop
 
@@ -12267,7 +12263,8 @@ package body Exp_Ch4 is
                                  N_Procedure_Call_Statement,
                                  N_Simple_Return_Statement)
                then
-                  return Par;
+                  Hook_Context := Par;
+                  goto Hook_Context_Found;
 
                --  Prevent the search from going too far
 
@@ -12280,25 +12277,66 @@ package body Exp_Ch4 is
 
             --  Return the topmost short circuit operator
 
-            return Top;
+            Hook_Context := Top;
          end if;
-      end Find_Enclosing_Context;
+
+      <<Hook_Context_Found>>
+
+         --  Special case for Boolean EWAs: capture expression in a temporary,
+         --  whose declaration will serve as the context around which to insert
+         --  finalization code. The finalization thus remains local to the
+         --  specific condition being evaluated.
+
+         if Is_Boolean_Type (Etype (N)) then
+
+            --  In this case, the finalization context is chosen so that
+            --  we know at finalization point that the hook pointer is
+            --  never null, so no need for a test, we can call the finalizer
+            --  unconditionally.
+
+            Finalize_Always := True;
+
+            declare
+               Loc  : constant Source_Ptr := Sloc (N);
+               Temp : constant Entity_Id := Make_Temporary (Loc, 'E', N);
+            begin
+               Append_To (Actions (N),
+                 Make_Object_Declaration (Loc,
+                   Defining_Identifier => Temp,
+                   Constant_Present    => True,
+                   Object_Definition   =>
+                     New_Occurrence_Of (Etype (N), Loc),
+                   Expression          => Expression (N)));
+               Finalization_Context := Last (Actions (N));
+
+               Analyze (Last (Actions (N)));
+
+               Set_Expression (N, New_Occurrence_Of (Temp, Loc));
+               Analyze (Expression (N));
+            end;
+
+         else
+            Finalize_Always := False;
+            Finalization_Context := Hook_Context;
+         end if;
+      end Find_Enclosing_Contexts;
 
       --  Local variables
 
-      Context   : constant Node_Id    := Find_Enclosing_Context (Rel_Node);
       Loc       : constant Source_Ptr := Sloc (Decl);
       Obj_Id    : constant Entity_Id  := Defining_Identifier (Decl);
       Obj_Typ   : constant Node_Id    := Etype (Obj_Id);
       Desig_Typ : Entity_Id;
       Expr      : Node_Id;
-      Fin_Call  : Node_Id;
+      Fin_Stmts : List_Id;
       Ptr_Id    : Entity_Id;
       Temp_Id   : Entity_Id;
 
    --  Start of processing for Process_Transient_Object
 
    begin
+      Find_Enclosing_Contexts (Rel_Node);
+
       --  Step 1: Create the access type which provides a reference to the
       --  transient controlled object.
 
@@ -12315,7 +12353,7 @@ package body Exp_Ch4 is
 
       Ptr_Id := Make_Temporary (Loc, 'A');
 
-      Insert_Action (Context,
+      Insert_Action (Hook_Context,
         Make_Full_Type_Declaration (Loc,
           Defining_Identifier => Ptr_Id,
           Type_Definition     =>
@@ -12330,7 +12368,7 @@ package body Exp_Ch4 is
 
       Temp_Id := Make_Temporary (Loc, 'T');
 
-      Insert_Action (Context,
+      Insert_Action (Hook_Context,
         Make_Object_Declaration (Loc,
           Defining_Identifier => Temp_Id,
           Object_Definition   => New_Reference_To (Ptr_Id, Loc)));
@@ -12363,10 +12401,18 @@ package body Exp_Ch4 is
       --      <or>
       --    Temp := Obj_Id'Unrestricted_Access;
 
-      Insert_After_And_Analyze (Decl,
-        Make_Assignment_Statement (Loc,
-          Name       => New_Reference_To (Temp_Id, Loc),
-          Expression => Expr));
+      if Finalization_Context /= Hook_Context then
+         Insert_Action (Finalization_Context,
+           Make_Assignment_Statement (Loc,
+             Name       => New_Reference_To (Temp_Id, Loc),
+             Expression => Expr));
+
+      else
+         Insert_After_And_Analyze (Decl,
+           Make_Assignment_Statement (Loc,
+             Name       => New_Reference_To (Temp_Id, Loc),
+             Expression => Expr));
+      end if;
 
       --  Step 4: Finalize the transient controlled object after the context
       --  has been evaluated/elaborated. Generate:
@@ -12383,26 +12429,29 @@ package body Exp_Ch4 is
       --  insert the finalization code after the return statement as this will
       --  render it unreachable.
 
-      if Nkind (Context) /= N_Simple_Return_Statement then
-         Fin_Call :=
-           Make_Implicit_If_Statement (Decl,
-             Condition =>
-               Make_Op_Ne (Loc,
-                 Left_Opnd  => New_Reference_To (Temp_Id, Loc),
-                 Right_Opnd => Make_Null (Loc)),
+      if Nkind (Finalization_Context) /= N_Simple_Return_Statement then
+         Fin_Stmts := New_List (
+           Make_Final_Call
+             (Obj_Ref =>
+                Make_Explicit_Dereference (Loc,
+                  Prefix => New_Reference_To (Temp_Id, Loc)),
+              Typ     => Desig_Typ),
 
-             Then_Statements => New_List (
-               Make_Final_Call
-                 (Obj_Ref =>
-                    Make_Explicit_Dereference (Loc,
-                      Prefix => New_Reference_To (Temp_Id, Loc)),
-                  Typ     => Desig_Typ),
+           Make_Assignment_Statement (Loc,
+             Name       => New_Reference_To (Temp_Id, Loc),
+             Expression => Make_Null (Loc)));
 
-               Make_Assignment_Statement (Loc,
-                 Name       => New_Reference_To (Temp_Id, Loc),
-                 Expression => Make_Null (Loc))));
+         if not Finalize_Always then
+            Fin_Stmts := New_List (
+              Make_Implicit_If_Statement (Decl,
+                Condition =>
+                  Make_Op_Ne (Loc,
+                    Left_Opnd  => New_Reference_To (Temp_Id, Loc),
+                    Right_Opnd => Make_Null (Loc)),
+                Then_Statements => Fin_Stmts));
+         end if;
 
-         Insert_Action_After (Context, Fin_Call);
+         Insert_Actions_After (Finalization_Context, Fin_Stmts);
       end if;
    end Process_Transient_Object;
 
index 2e0185ea7fab3f85fcb021ec8b999b9bd5f1de72..c260207550de4035f477f7183f16422021f54e60 100644 (file)
@@ -2706,18 +2706,36 @@ package body Exp_Util is
         (N : Node_Id;
          S : Boolean)
       is
-         Cond : Node_Id;
-         Sens : Boolean;
+         Cond      : Node_Id;
+         Prev_Cond : Node_Id;
+         Sens      : Boolean;
 
       begin
          Cond := N;
          Sens := S;
 
-         --  Deal with NOT operators, inverting sense
+         loop
+            Prev_Cond := Cond;
 
-         while Nkind (Cond) = N_Op_Not loop
-            Cond := Right_Opnd (Cond);
-            Sens := not Sens;
+            --  Deal with NOT operators, inverting sense
+
+            while Nkind (Cond) = N_Op_Not loop
+               Cond := Right_Opnd (Cond);
+               Sens := not Sens;
+            end loop;
+
+            --  Deal with conversions, qualifications, and expressions with
+            --  actions.
+
+            while Nkind_In (Cond,
+                    N_Type_Conversion,
+                    N_Qualified_Expression,
+                    N_Expression_With_Actions)
+            loop
+               Cond := Expression (Cond);
+            end loop;
+
+            exit when Cond = Prev_Cond;
          end loop;
 
          --  Deal with AND THEN and AND cases
@@ -2798,8 +2816,15 @@ package body Exp_Util is
 
             return;
 
-            --  Case of Boolean variable reference, return as though the
-            --  reference had said var = True.
+         elsif Nkind_In (Cond,
+                 N_Type_Conversion,
+                 N_Qualified_Expression,
+                 N_Expression_With_Actions)
+         then
+            Cond := Expression (Cond);
+
+         --  Case of Boolean variable reference, return as though the
+         --  reference had said var = True.
 
          else
             if Is_Entity_Name (Cond) and then Ent = Entity (Cond) then
@@ -3406,8 +3431,13 @@ package body Exp_Util is
 
             when N_Expression_With_Actions =>
                if N = Expression (P) then
-                  Insert_List_After_And_Analyze
-                    (Last (Actions (P)), Ins_Actions);
+                  if Is_Empty_List (Actions (P)) then
+                     Append_List_To (Actions (P), Ins_Actions);
+                     Analyze_List (Actions (P));
+                  else
+                     Insert_List_After_And_Analyze
+                       (Last (Actions (P)), Ins_Actions);
+                  end if;
                   return;
                end if;
 
@@ -6702,6 +6732,14 @@ package body Exp_Util is
             when N_Explicit_Dereference =>
                return Safe_Prefixed_Reference (N);
 
+            --  An expression with action is side effect free if its expression
+            --  is side effect free and it has no actions.
+
+            when N_Expression_With_Actions =>
+               return Is_Empty_List (Actions (N))
+                        and then
+                      Side_Effect_Free (Expression (N));
+
             --  A call to _rep_to_pos is side effect free, since we generate
             --  this pure function call ourselves. Moreover it is critically
             --  important to make this exception, since otherwise we can have
@@ -7103,7 +7141,6 @@ package body Exp_Util is
          end if;
 
          Def_Id := Make_Temporary (Loc, 'R', Exp);
-         Set_Etype (Def_Id, Exp_Type);
 
          --  The regular expansion of functions with side effects involves the
          --  generation of an access type to capture the return value found on
@@ -7780,7 +7817,14 @@ package body Exp_Util is
                Set_Entity_Current_Value (Right_Opnd (Cond));
             end if;
 
-            --  Check possible boolean variable reference
+         elsif Nkind_In (Cond,
+                 N_Type_Conversion,
+                 N_Qualified_Expression,
+                 N_Expression_With_Actions)
+         then
+            Set_Expression_Current_Value (Expression (Cond));
+
+         --  Check possible boolean variable reference
 
          else
             Set_Entity_Current_Value (Cond);
index 6aef3843016d4917444667c814902a79bc81213f..0ba9d8fa14a0e37b533555196df7341b15bfa262 100644 (file)
@@ -7279,6 +7279,16 @@ package body Sem_Ch13 is
             when N_Qualified_Expression =>
                return Get_RList (Expression (Exp));
 
+            --  Expression with actions: if no actions, dig out expression
+
+            when N_Expression_With_Actions =>
+               if Is_Empty_List (Actions (Exp)) then
+                  return Get_RList (Expression (Exp));
+
+               else
+                  raise Non_Static;
+               end if;
+
             --  Xor operator
 
             when N_Op_Xor =>
index 805dc68a9238162ce850854f054eaabe29971d63..ca7310585b4f388ab30c546ca0b9a1f9a58db9a0 100644 (file)
@@ -2095,10 +2095,19 @@ package body Sem_Res is
 
       Check_Parameterless_Call (N);
 
+      --  The resolution of an Expression_With_Actions is determined by
+      --  its Expression.
+
+      if Nkind (N) = N_Expression_With_Actions then
+         Resolve (Expression (N), Typ);
+
+         Found := True;
+         Expr_Type := Etype (Expression (N));
+
       --  If not overloaded, then we know the type, and all that needs doing
       --  is to check that this type is compatible with the context.
 
-      if not Is_Overloaded (N) then
+      elsif not Is_Overloaded (N) then
          Found := Covers (Typ, Etype (N));
          Expr_Type := Etype (N);
 
@@ -7274,6 +7283,17 @@ package body Sem_Res is
    procedure Resolve_Expression_With_Actions (N : Node_Id; Typ : Entity_Id) is
    begin
       Set_Etype (N, Typ);
+
+      --  If N has no actions, and its expression has been constant folded,
+      --  then rewrite N as just its expression. Note, we can't do this in
+      --  the general case of Is_Empty_List (Actions (N)) as this would cause
+      --  Expression (N) to be expanded again.
+
+      if Is_Empty_List (Actions (N))
+        and then Compile_Time_Known_Value (Expression (N))
+      then
+         Rewrite (N, Expression (N));
+      end if;
    end Resolve_Expression_With_Actions;
 
    ---------------------------
@@ -8996,6 +9016,30 @@ package body Sem_Res is
       R     : constant Node_Id   := Right_Opnd (N);
 
    begin
+      --  Ensure all actions associated with the left operand (e.g.
+      --  finalization of transient controlled objects) are fully evaluated
+      --  locally within an expression with actions. This is particularly
+      --  helpful for coverage analysis. However this should not happen in
+      --  generics.
+
+      if Expander_Active then
+         declare
+            Reloc_L : constant Node_Id := Relocate_Node (L);
+         begin
+            Save_Interps (Old_N => L, New_N => Reloc_L);
+
+            Rewrite (L,
+              Make_Expression_With_Actions (Sloc (L),
+                Actions    => New_List,
+                Expression => Reloc_L));
+
+            --  Set Comes_From_Source on L to preserve warnings for unset
+            --  reference.
+
+            Set_Comes_From_Source (L, Comes_From_Source (Reloc_L));
+         end;
+      end if;
+
       Resolve (L, B_Typ);
       Resolve (R, B_Typ);
 
index f0dcd0333c33c112ee6c7d7172d14ccc2b61f07b..6e9e7fe464fb410ce9fcc157461bc53d414186c3 100644 (file)
@@ -6777,6 +6777,12 @@ package body Sem_Util is
                    and then
                 Has_No_Obvious_Side_Effects (Right_Opnd (N));
 
+      elsif Nkind (N) = N_Expression_With_Actions
+              and then
+            Is_Empty_List (Actions (N))
+      then
+         return Has_No_Obvious_Side_Effects (Expression (N));
+
       elsif Nkind (N) in N_Has_Entity then
          return Present (Entity (N))
            and then Ekind_In (Entity (N), E_Variable,
index 493c5e4f517dd26a34c702fc9ba1dac98bd8bdd6..dd6a904daa6ca3bf8376ac743a9576e5b609efa4 100644 (file)
@@ -1310,6 +1310,7 @@ package body Sem_Warn is
                   UR := Original_Node (UR);
                   while Nkind (UR) = N_Type_Conversion
                     or else Nkind (UR) = N_Qualified_Expression
+                    or else Nkind (UR) = N_Expression_With_Actions
                   loop
                      UR := Expression (UR);
                   end loop;
@@ -2034,9 +2035,12 @@ package body Sem_Warn is
                Check_Unset_Reference (Pref);
             end;
 
-         --  For type conversions or qualifications examine the expression
+         --  For type conversions, qualifications, or expressions with actions,
+         --  examine the expression.
 
-         when N_Type_Conversion | N_Qualified_Expression =>
+         when N_Type_Conversion         |
+              N_Qualified_Expression    |
+              N_Expression_With_Actions =>
             Check_Unset_Reference (Expression (N));
 
          --  For explicit dereference, always check prefix, which will generate