[COMMITTED,25/31] ada: Cleanup preanalysis of static expressions (part 2)

Message ID 20250107125350.619654-25-poulhies@adacore.com
State New
Headers
Series [COMMITTED,01/31] ada: Restrict previous change made to expansion of allocators |

Commit Message

Marc Poulhiès Jan. 7, 2025, 12:53 p.m. UTC
  From: Javier Miranda <miranda@adacore.com>

According to RM 13.14(8/4), a static expression in an aspect specification
does not cause freezing; however, the frontend performs many calls to
Preanalyze_Spec_Expression made during the analysis of aspects. This
patch, suggested by Eric Botcazou, takes care of this additional code
cleanup which requires also replacing many occurrences of the global
variable In_Spec_Expression by calls to Preanalysis_Active.

gcc/ada/ChangeLog:

	* exp_util.adb (Insert_Actions): Document behavior under strict
	preanalysis.
	* sem.ads (In_Strict_Preanalysis): New subprogram.
	(Preanalysis_Active): Replace 'and' operator by 'and then'.
	* sem.adb (In_Strict_Preanalysis): Ditto.
	* sem_attr.adb (Check_Dereference): Replace In_Spec_Expression
	occurrence by call to Preanalysis_Active, and document it.
	(Resolve_Attribute [Atribute_Access]): Ditto.
	(Eval_Attribute): No evaluation under strict preanalysis.
	(Validate_Static_Object_Name): No action under strict preanalysis.
	* sem_ch13.adb (Check_Aspect_At_End_Of_Declarations): Replace
	calls to Preanalyze_Spec_Expression by calls to Preanalyze_And_Resolve.
	(Check_Aspect_At_Freeze_Point): Ditto.
	(Resolve_Aspect_Expressions [Dynamic/Static/Predicate aspects]): Code
	cleanup adjusting the code to emulate Preanalyze_And_Resolve, instead
	of Preanalyze_Spec_Expression.
	(Resolve_Aspect_Expressions [CPU/Interrupt_Priority/Priority/
	Storage_Size aspects]): Replace calls to Preanalyze_Spec_Expression
	by call to Preanalyze_And _Resolve.
	* sem_ch3.adb (Analyze_Object_Declaration): Replace In_Spec_Expression
	occurrence by call to Preanalysis_Active.
	(Find_Type_Of_Object): Add documentation.
	* sem_ch4.adb (Analyze_Case_Expression): Replace In_Spec_Expression
	occurrence by call to Preanalysis_Active.
	* sem_ch6.adb (Analyze_Expression_Function): Minor code reorganization
	moving the code preanalyzing the expression after the new body has
	been inserted in the tree to ensure that its Parent attribute is
	available for preanalysis.
	* sem_cat.adb (Validate_Static_Object_Name): No action under strict
	preanalysis.
	* sem_elab.adb (Check_For_Eliminated_Subprogram): Replace In_Spec_Expression
	occurrence by call to Preanalysis_Active.
	* sem_eval.adb (Eval_Intrinsic_Call [Name_Enclosing_Entity]): Ditto.
	* sem_elim.adb (Check_For_Eliminated_Subprogram): Ditto.
	* sem_res.adb (Resolve_Entity_Name): Ditto.

Tested on x86_64-pc-linux-gnu, committed on master.

---
 gcc/ada/exp_util.adb | 16 +++++++--------
 gcc/ada/sem.adb      | 11 ++++++++++-
 gcc/ada/sem.ads      |  5 +++++
 gcc/ada/sem_attr.adb | 25 ++++++++++++++++--------
 gcc/ada/sem_cat.adb  |  1 +
 gcc/ada/sem_ch13.adb | 25 +++++++++++-------------
 gcc/ada/sem_ch3.adb  |  7 +++++--
 gcc/ada/sem_ch4.adb  |  2 +-
 gcc/ada/sem_ch6.adb  | 46 ++++++++++++++++++++++----------------------
 gcc/ada/sem_elab.adb |  2 +-
 gcc/ada/sem_elim.adb |  5 +++--
 gcc/ada/sem_eval.adb |  2 +-
 gcc/ada/sem_res.adb  |  2 +-
 13 files changed, 87 insertions(+), 62 deletions(-)
  

Patch

diff --git a/gcc/ada/exp_util.adb b/gcc/ada/exp_util.adb
index 66ba73226ed..69d6e25794e 100644
--- a/gcc/ada/exp_util.adb
+++ b/gcc/ada/exp_util.adb
@@ -7708,20 +7708,20 @@  package body Exp_Util is
          return;
       end if;
 
-      --  Insert the action when the context is "Handling of Default and Per-
-      --  Object Expressions" only when requested by the caller.
-
-      if Spec_Expr_OK then
-         null;
-
       --  Ignore insert of actions from inside default expression (or other
       --  similar "spec expression") in the special spec-expression analyze
       --  mode. Any insertions at this point have no relevance, since we are
       --  only doing the analyze to freeze the types of any static expressions.
       --  See section "Handling of Default and Per-Object Expressions" in the
-      --  spec of package Sem for further details.
+      --  spec of package Sem for further details. However, if the user does
+      --  nevertheless request the insert, then obey it.
+
+      --  Under strict preanalysis we cannot ignore insert of actions because
+      --  we may be adding to the tree a subtype declaration that is required
+      --  for proper preanalysis (see Sem_Ch3.Find_Type_Of_Object).
 
-      elsif In_Spec_Expression then
+      if In_Spec_Expression and then not Spec_Expr_OK then
+         pragma Assert (not In_Strict_Preanalysis);
          return;
       end if;
 
diff --git a/gcc/ada/sem.adb b/gcc/ada/sem.adb
index a7e3df9f06e..9b013995b8a 100644
--- a/gcc/ada/sem.adb
+++ b/gcc/ada/sem.adb
@@ -1338,13 +1338,22 @@  package body Sem is
       Scope_Stack.Locked := True;
    end Lock;
 
+   ---------------------------
+   -- In_Strict_Preanalysis --
+   ---------------------------
+
+   function In_Strict_Preanalysis return Boolean is
+   begin
+      return Preanalysis_Active and then not In_Spec_Expression;
+   end In_Strict_Preanalysis;
+
    ------------------------
    -- Preanalysis_Active --
    ------------------------
 
    function Preanalysis_Active return Boolean is
    begin
-      return not Full_Analysis and not Expander_Active;
+      return not Full_Analysis and then not Expander_Active;
    end Preanalysis_Active;
 
    ----------------
diff --git a/gcc/ada/sem.ads b/gcc/ada/sem.ads
index 89b616f0bd4..f317479d461 100644
--- a/gcc/ada/sem.ads
+++ b/gcc/ada/sem.ads
@@ -703,6 +703,11 @@  package Sem is
    --  This function returns True if an explicit pragma Suppress for check C
    --  is present in the package defining E.
 
+   function In_Strict_Preanalysis return Boolean;
+   pragma Inline (In_Strict_Preanalysis);
+   --  Determine whether preanalysis is active at the point of invocation
+   --  and we are not processing a Spec Expression.
+
    function Preanalysis_Active return Boolean;
    pragma Inline (Preanalysis_Active);
    --  Determine whether preanalysis is active at the point of invocation
diff --git a/gcc/ada/sem_attr.adb b/gcc/ada/sem_attr.adb
index 39725d23442..e74d3051b34 100644
--- a/gcc/ada/sem_attr.adb
+++ b/gcc/ada/sem_attr.adb
@@ -2106,11 +2106,12 @@  package body Sem_Attr is
             --  designated type of the access type, since the type of the
             --  referenced array is this type (see AI95-00106).
 
-            --  As done elsewhere, freezing must not happen when preanalyzing
-            --  a pre- or postcondition or a default value for an object or for
-            --  a formal parameter.
+            --    However, we must not freeze the designated type during
+            --    preanalysis; neither under strict preanalysis nor when
+            --    preanalyzing a pre- or postcondition or a default value
+            --    for an object or for a formal parameter.
 
-            if not In_Spec_Expression then
+            if not Preanalysis_Active then
                Freeze_Before (N, Designated_Type (P_Type));
             end if;
 
@@ -8139,6 +8140,13 @@  package body Sem_Attr is
 
       if Nkind (N) /= N_Attribute_Reference then
          return;
+
+      --  No evaluation required under strict preanalysis because locating
+      --  static expressions is not needed; this also minimizes making tree
+      --  modifications during strict preanalysis.
+
+      elsif In_Strict_Preanalysis then
+         return;
       end if;
 
       Aname := Attribute_Name (N);
@@ -11342,10 +11350,11 @@  package body Sem_Attr is
                   end loop;
 
                   --  If Prefix is a subprogram name, this reference freezes,
-                  --  but not if within spec expression mode. The profile of
-                  --  the subprogram is not frozen at this point.
+                  --  but not during preanalysis (including preanalysis of
+                  --  spec expressions). The profile of the subprogram is not
+                  --  frozen at this point.
 
-                  if not In_Spec_Expression then
+                  if not Preanalysis_Active then
                      Freeze_Before (N, Entity (P), Do_Freeze_Profile => False);
                   end if;
 
@@ -11354,7 +11363,7 @@  package body Sem_Attr is
                --  If it is an object, complete its resolution.
 
                elsif Is_Overloadable (Entity (P)) then
-                  if not In_Spec_Expression then
+                  if not Preanalysis_Active then
                      Freeze_Before (N, Entity (P), Do_Freeze_Profile => False);
                   end if;
 
diff --git a/gcc/ada/sem_cat.adb b/gcc/ada/sem_cat.adb
index d8928119512..0bd976cbf65 100644
--- a/gcc/ada/sem_cat.adb
+++ b/gcc/ada/sem_cat.adb
@@ -2177,6 +2177,7 @@  package body Sem_Cat is
         or else not Comes_From_Source (N)
         or else In_Subprogram_Or_Concurrent_Unit
         or else Ekind (Current_Scope) = E_Block
+        or else In_Strict_Preanalysis
       then
          return;
 
diff --git a/gcc/ada/sem_ch13.adb b/gcc/ada/sem_ch13.adb
index a9aba1de6e4..2beb6b95daf 100644
--- a/gcc/ada/sem_ch13.adb
+++ b/gcc/ada/sem_ch13.adb
@@ -10039,7 +10039,7 @@  package body Sem_Ch13 is
 
                   --  If the predicate pragma comes from an aspect, replace the
                   --  saved expression because we need the subtype references
-                  --  replaced for the calls to Preanalyze_Spec_Expression in
+                  --  replaced for the calls to Preanalyze_And_Resolve in
                   --  Check_Aspect_At_xxx routines.
 
                   if Present (Asp) then
@@ -10853,12 +10853,12 @@  package body Sem_Ch13 is
                      | Aspect_Static_Predicate
             then
                Push_Type (Ent);
-               Preanalyze_Spec_Expression (Freeze_Expr, Standard_Boolean);
+               Preanalyze_And_Resolve (Freeze_Expr, Standard_Boolean);
                Pop_Type (Ent);
 
             elsif A_Id = Aspect_Priority then
                Push_Type (Ent);
-               Preanalyze_Spec_Expression (Freeze_Expr, Any_Integer);
+               Preanalyze_And_Resolve (Freeze_Expr, Any_Integer);
                Pop_Type (Ent);
 
             else
@@ -10916,13 +10916,14 @@  package body Sem_Ch13 is
                      | Aspect_Static_Predicate
          then
             Push_Type (Ent);
-            Preanalyze_Spec_Expression (End_Decl_Expr, T);
+            Preanalyze_And_Resolve (End_Decl_Expr, T);
             Pop_Type (Ent);
 
          elsif A_Id = Aspect_Predicate_Failure then
-            Preanalyze_Spec_Expression (End_Decl_Expr, Standard_String);
+            Preanalyze_And_Resolve (End_Decl_Expr, Standard_String);
+
          elsif Present (End_Decl_Expr) then
-            Preanalyze_Spec_Expression (End_Decl_Expr, T);
+            Preanalyze_And_Resolve (End_Decl_Expr, T);
          end if;
 
          Err :=
@@ -11346,7 +11347,7 @@  package body Sem_Ch13 is
       --  Do the preanalyze call
 
       if Present (Expression (ASN)) then
-         Preanalyze_Spec_Expression (Expression (ASN), T);
+         Preanalyze_And_Resolve (Expression (ASN), T);
       end if;
    end Check_Aspect_At_Freeze_Point;
 
@@ -16341,19 +16342,16 @@  package body Sem_Ch13 is
                      --  name resolution errors if the predicate function has
                      --  not been built yet.
 
-                     --  Note that we cannot use Preanalyze_Spec_Expression
+                     --  Note that we cannot use Preanalyze_And_Resolve
                      --  directly because of the special handling required for
                      --  quantifiers (see comments on Resolve_Aspect_Expression
                      --  above) but we need to emulate it properly.
 
                      if No (Predicate_Function (E)) then
                         declare
-                           Save_In_Spec_Expression : constant Boolean :=
-                                                       In_Spec_Expression;
                            Save_Full_Analysis : constant Boolean :=
                                                   Full_Analysis;
                         begin
-                           In_Spec_Expression := True;
                            Full_Analysis := False;
                            Expander_Mode_Save_And_Set (False);
                            Push_Type (E);
@@ -16361,7 +16359,6 @@  package body Sem_Ch13 is
                            Pop_Type (E);
                            Expander_Mode_Restore;
                            Full_Analysis := Save_Full_Analysis;
-                           In_Spec_Expression := Save_In_Spec_Expression;
                         end;
                      end if;
 
@@ -16404,7 +16401,7 @@  package body Sem_Ch13 is
                      | Aspect_Priority
                   =>
                      Push_Type (E);
-                     Preanalyze_Spec_Expression (Expr, Any_Integer);
+                     Preanalyze_And_Resolve (Expr, Any_Integer);
                      Pop_Type (E);
 
                   --  Ditto for Storage_Size. Any other aspects that carry
@@ -16412,7 +16409,7 @@  package body Sem_Ch13 is
                   --  relevant to the misuse of deferred constants.
 
                   when Aspect_Storage_Size =>
-                     Preanalyze_Spec_Expression (Expr, Any_Integer);
+                     Preanalyze_And_Resolve (Expr, Any_Integer);
 
                   when others =>
                      if Present (Expr) then
diff --git a/gcc/ada/sem_ch3.adb b/gcc/ada/sem_ch3.adb
index 7bedc043c8d..f0ce27b5e23 100644
--- a/gcc/ada/sem_ch3.adb
+++ b/gcc/ada/sem_ch3.adb
@@ -4575,7 +4575,8 @@  package body Sem_Ch3 is
            and then Is_Itype (T)
          then
             Set_Has_Delayed_Freeze (T);
-         elsif not In_Spec_Expression then
+
+         elsif not Preanalysis_Active then
             Freeze_Before (N, T);
          end if;
       end if;
@@ -18796,7 +18797,9 @@  package body Sem_Ch3 is
          end if;
 
          --  When generating code, insert subtype declaration ahead of
-         --  declaration that generated it.
+         --  declaration that generated it. Similar behavior required under
+         --  preanalysis (including strict preanalysis) to perform the
+         --  minimum decoration, and avoid reporting spurious errors.
 
          Insert_Action (Obj_Def,
            Make_Subtype_Declaration (Sloc (P),
diff --git a/gcc/ada/sem_ch4.adb b/gcc/ada/sem_ch4.adb
index 7bd30d6993e..6ec351e42a6 100644
--- a/gcc/ada/sem_ch4.adb
+++ b/gcc/ada/sem_ch4.adb
@@ -1795,7 +1795,7 @@  package body Sem_Ch4 is
 
       if Is_OK_Static_Subtype (Exp_Type)
         and then Has_Static_Predicate_Aspect (Exp_Type)
-        and then In_Spec_Expression
+        and then Preanalysis_Active
       then
          null;
 
diff --git a/gcc/ada/sem_ch6.adb b/gcc/ada/sem_ch6.adb
index d81bdc50ee0..9cd135d48ce 100644
--- a/gcc/ada/sem_ch6.adb
+++ b/gcc/ada/sem_ch6.adb
@@ -533,29 +533,6 @@  package body Sem_Ch6 is
          Set_Corresponding_Body (N, Defining_Entity (New_Body));
          Set_Corresponding_Spec (New_Body, Def_Id);
 
-         --  Within a generic preanalyze the original expression for name
-         --  capture. The body is also generated but plays no role in
-         --  this because it is not part of the original source.
-         --  If this is an ignored Ghost entity, analysis of the generated
-         --  body is needed to hide external references (as is done in
-         --  Analyze_Subprogram_Body) after which the subprogram profile
-         --  can be frozen, which is needed to expand calls to such an ignored
-         --  Ghost subprogram.
-
-         if Inside_A_Generic then
-            Set_Has_Completion (Def_Id, not Is_Ignored_Ghost_Entity (Def_Id));
-            Push_Scope (Def_Id);
-            Install_Formals (Def_Id);
-            Preanalyze_Spec_Expression (Expr, Typ);
-            End_Scope;
-         else
-            Push_Scope (Def_Id);
-            Install_Formals (Def_Id);
-            Preanalyze_Spec_Expression (Expr, Typ);
-            Check_Limited_Return (Orig_N, Expr, Typ);
-            End_Scope;
-         end if;
-
          --  If this is a wrapper created in an instance for a formal
          --  subprogram, insert body after declaration, to be analyzed when the
          --  enclosing instance is analyzed.
@@ -591,6 +568,29 @@  package body Sem_Ch6 is
             end;
          end if;
 
+         --  Within a generic preanalyze the original expression for name
+         --  capture. The body is also generated but plays no role in
+         --  this because it is not part of the original source.
+         --  If this is an ignored Ghost entity, analysis of the generated
+         --  body is needed to hide external references (as is done in
+         --  Analyze_Subprogram_Body) after which the subprogram profile
+         --  can be frozen, which is needed to expand calls to such an ignored
+         --  Ghost subprogram.
+
+         if Inside_A_Generic then
+            Set_Has_Completion (Def_Id, not Is_Ignored_Ghost_Entity (Def_Id));
+            Push_Scope (Def_Id);
+            Install_Formals (Def_Id);
+            Preanalyze_Spec_Expression (Expr, Typ);
+            End_Scope;
+         else
+            Push_Scope (Def_Id);
+            Install_Formals (Def_Id);
+            Preanalyze_Spec_Expression (Expr, Typ);
+            Check_Limited_Return (Orig_N, Expr, Typ);
+            End_Scope;
+         end if;
+
          --  In the case of an expression function marked with the aspect
          --  Static, we need to check the requirement that the function's
          --  expression is a potentially static expression. This is done
diff --git a/gcc/ada/sem_elab.adb b/gcc/ada/sem_elab.adb
index 414caf2edaa..1fa714d229e 100644
--- a/gcc/ada/sem_elab.adb
+++ b/gcc/ada/sem_elab.adb
@@ -17389,7 +17389,7 @@  package body Sem_Elab is
       --  Nothing to do if call is being preanalyzed, as when within a
       --  pre/postcondition, a predicate, or an invariant.
 
-      elsif In_Spec_Expression then
+      elsif Preanalysis_Active then
          return;
       end if;
 
diff --git a/gcc/ada/sem_elim.adb b/gcc/ada/sem_elim.adb
index d553950dbd7..2bff3dc4ae2 100644
--- a/gcc/ada/sem_elim.adb
+++ b/gcc/ada/sem_elim.adb
@@ -728,9 +728,10 @@  package body Sem_Elim is
    begin
       --  No check needed within a default expression for a formal, since this
       --  is not really a use, and the expression (a call or attribute) may
-      --  never be used if the enclosing subprogram is itself eliminated.
+      --  never be used if the enclosing subprogram is itself eliminated. Same
+      --  under strict preanalysis.
 
-      if In_Spec_Expression then
+      if Preanalysis_Active then
          return;
       end if;
 
diff --git a/gcc/ada/sem_eval.adb b/gcc/ada/sem_eval.adb
index c55e4d3bb24..399b22d0c52 100644
--- a/gcc/ada/sem_eval.adb
+++ b/gcc/ada/sem_eval.adb
@@ -2927,7 +2927,7 @@  package body Sem_Eval is
             | Name_Source_Location
          =>
             if Inside_A_Generic
-              or else In_Spec_Expression
+              or else Preanalysis_Active
             then
                null;
             else
diff --git a/gcc/ada/sem_res.adb b/gcc/ada/sem_res.adb
index 889cbd307b4..5f990f3dc4e 100644
--- a/gcc/ada/sem_res.adb
+++ b/gcc/ada/sem_res.adb
@@ -8147,7 +8147,7 @@  package body Sem_Res is
            and then Comes_From_Source (E)
            and then No (Constant_Value (E))
            and then Is_Frozen (Etype (E))
-           and then not In_Spec_Expression
+           and then not Preanalysis_Active
            and then not Is_Imported (E)
            and then Nkind (Parent (E)) /= N_Object_Renaming_Declaration
          then