public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc r12-5733] [Ada] Enable expansion of dispatching equality for GNATprove
@ 2021-12-02 16:29 Pierre-Marie de Rodat
0 siblings, 0 replies; only message in thread
From: Pierre-Marie de Rodat @ 2021-12-02 16:29 UTC (permalink / raw)
To: gcc-cvs
https://gcc.gnu.org/g:eca89ac6e73026a8606e05e6f0486f963c02c4bc
commit r12-5733-geca89ac6e73026a8606e05e6f0486f963c02c4bc
Author: Piotr Trojanek <trojanek@adacore.com>
Date: Mon Nov 22 19:01:33 2021 +0100
[Ada] Enable expansion of dispatching equality for GNATprove
gcc/ada/
* exp_ch13.ads (Expand_N_Freeze_Entity): Add note about a SPARK
twin.
* exp_ch3.ads (Freeze_Type): Likewise.
* exp_spark.adb (Expand_SPARK_N_Freeze_Entity): Mimic what is
done in Freeze_Entity.
(SPARK_Freeze_Type): Mimic what is done in Freeze_Type; add call
to Make_Predefined_Primitive_Eq_Spec.
Diff:
---
gcc/ada/exp_ch13.ads | 3 +
gcc/ada/exp_ch3.ads | 3 +
gcc/ada/exp_spark.adb | 289 +++++++++++++++++++++++++++++++++++++++++++++++---
3 files changed, 280 insertions(+), 15 deletions(-)
diff --git a/gcc/ada/exp_ch13.ads b/gcc/ada/exp_ch13.ads
index 1c5301dca1d..f5dcfe097e2 100644
--- a/gcc/ada/exp_ch13.ads
+++ b/gcc/ada/exp_ch13.ads
@@ -32,6 +32,9 @@ package Exp_Ch13 is
procedure Expand_N_Attribute_Definition_Clause (N : Node_Id);
procedure Expand_N_Free_Statement (N : Node_Id);
procedure Expand_N_Freeze_Entity (N : Node_Id);
+ -- Note: for GNATprove we have a minimal variant of this routine in
+ -- Exp_SPARK.Expand_SPARK_N_Freeze_Entity. They need to be kept in sync.
+
procedure Expand_N_Record_Representation_Clause (N : Node_Id);
end Exp_Ch13;
diff --git a/gcc/ada/exp_ch3.ads b/gcc/ada/exp_ch3.ads
index 61595eba8bd..c7648e6f419 100644
--- a/gcc/ada/exp_ch3.ads
+++ b/gcc/ada/exp_ch3.ads
@@ -114,6 +114,9 @@ package Exp_Ch3 is
-- delete the node if it is present just for front end purpose and we don't
-- want Gigi to see the node. This function can't delete the node itself
-- since it would confuse any remaining processing of the freeze node.
+ --
+ -- Note: for GNATprove we have a minimal variant of this routine in
+ -- Exp_SPARK.SPARK_Freeze_Type. They need to be kept in sync.
function Get_Simple_Init_Val
(Typ : Entity_Id;
diff --git a/gcc/ada/exp_spark.adb b/gcc/ada/exp_spark.adb
index bce745b2690..84927f8509c 100644
--- a/gcc/ada/exp_spark.adb
+++ b/gcc/ada/exp_spark.adb
@@ -29,15 +29,22 @@ with Einfo; use Einfo;
with Einfo.Entities; use Einfo.Entities;
with Einfo.Utils; use Einfo.Utils;
with Exp_Attr;
+with Exp_Ch3;
with Exp_Ch4;
with Exp_Ch5; use Exp_Ch5;
with Exp_Dbug; use Exp_Dbug;
with Exp_Util; use Exp_Util;
+with Ghost; use Ghost;
with Namet; use Namet;
with Nlists; use Nlists;
with Nmake; use Nmake;
+with Opt; use Opt;
+with Restrict; use Restrict;
+with Rident; use Rident;
with Rtsfind; use Rtsfind;
with Sem; use Sem;
+with Sem_Aux; use Sem_Aux;
+with Sem_Ch7; use Sem_Ch7;
with Sem_Ch8; use Sem_Ch8;
with Sem_Prag; use Sem_Prag;
with Sem_Res; use Sem_Res;
@@ -62,8 +69,10 @@ package body Exp_SPARK is
procedure Expand_SPARK_N_Delta_Aggregate (N : Node_Id);
-- Perform delta-aggregate-specific expansion
- procedure Expand_SPARK_N_Freeze_Type (E : Entity_Id);
- -- Build the DIC procedure of a type when needed, if not already done
+ procedure Expand_SPARK_N_Freeze_Entity (N : Node_Id);
+ -- Do a minimal expansion of freeze entities required by GNATprove. It is
+ -- a subset of what is done for GNAT in Exp_Ch13.Expand_N_Freeze_Entity.
+ -- Those two routines should be kept in sync.
procedure Expand_SPARK_N_Loop_Statement (N : Node_Id);
-- Perform loop-statement-specific expansion
@@ -80,6 +89,20 @@ package body Exp_SPARK is
procedure Expand_SPARK_Delta_Or_Update (Typ : Entity_Id; Aggr : Node_Id);
-- Common expansion for attribute Update and delta aggregates
+ procedure SPARK_Freeze_Type (N : Node_Id);
+ -- Do a minimal type freezing required by GNATprove. It is a subset of what
+ -- is done for GNAT in Exp_Ch3.Freeze_Type. Those two routines should be
+ -- kept in sync.
+ --
+ -- Currently in freezing we build the spec of dispatching equality. This
+ -- spec is needed to properly resolve references to the equality operator.
+ -- The body is not needed, because proof knows how to directly synthesize a
+ -- logical meaning for it. Also, for tagged types with extension the
+ -- expanded body would compare the _parent component, which is
+ -- intentionally not generated in the GNATprove mode.
+ --
+ -- We build the DIC procedure body here as well.
+
------------------
-- Expand_SPARK --
------------------
@@ -140,8 +163,12 @@ package body Exp_SPARK is
Expand_SPARK_N_Op_Ne (N);
when N_Freeze_Entity =>
+ -- Currently we only expand type freeze entities, so ignore other
+ -- freeze entites, because it is expensive to create a suitable
+ -- freezing environment.
+
if Is_Type (Entity (N)) then
- Expand_SPARK_N_Freeze_Type (Entity (N));
+ Expand_SPARK_N_Freeze_Entity (N);
end if;
-- In SPARK mode, no other constructs require expansion
@@ -350,23 +377,176 @@ package body Exp_SPARK is
end if;
end Expand_SPARK_Delta_Or_Update;
- --------------------------------
- -- Expand_SPARK_N_Freeze_Type --
- --------------------------------
+ ----------------------------------
+ -- Expand_SPARK_N_Freeze_Entity --
+ ----------------------------------
+
+ procedure Expand_SPARK_N_Freeze_Entity (N : Entity_Id) is
+ E : constant Entity_Id := Entity (N);
+
+ Action : Node_Id;
+ E_Scope : Entity_Id;
+ In_Other_Scope : Boolean;
+ In_Outer_Scope : Boolean;
- procedure Expand_SPARK_N_Freeze_Type (E : Entity_Id) is
begin
- -- When a DIC is inherited by a tagged type, it may need to be
- -- specialized to the descendant type, hence build a separate DIC
- -- procedure for it as done during regular expansion for compilation.
+ -- Here E is a type or a subprogram
- if Has_DIC (E) and then Is_Tagged_Type (E) then
- -- Why is this needed for DIC, but not for other aspects (such as
- -- Type_Invariant)???
+ E_Scope := Scope (E);
+
+ -- This is an error protection against previous errors
+
+ if No (E_Scope) then
+ Check_Error_Detected;
+ return;
+ end if;
+
+ -- The entity may be a subtype declared for a constrained record
+ -- component, in which case the relevant scope is the scope of
+ -- the record. This happens for class-wide subtypes created for
+ -- a constrained type extension with inherited discriminants.
+
+ if Is_Type (E_Scope)
+ and then not Is_Concurrent_Type (E_Scope)
+ then
+ E_Scope := Scope (E_Scope);
+
+ -- The entity may be a subtype declared for an iterator
+
+ elsif Ekind (E_Scope) = E_Loop then
+ E_Scope := Scope (E_Scope);
+ end if;
+
+ -- If we are freezing entities defined in protected types, they belong
+ -- in the enclosing scope, given that the original type has been
+ -- expanded away. The same is true for entities in task types, in
+ -- particular the parameter records of entries (Entities in bodies are
+ -- all frozen within the body). If we are in the task body, this is a
+ -- proper scope. If we are within a subprogram body, the proper scope
+ -- is the corresponding spec. This may happen for itypes generated in
+ -- the bodies of protected operations.
+
+ if Ekind (E_Scope) = E_Protected_Type
+ or else (Ekind (E_Scope) = E_Task_Type
+ and then not Has_Completion (E_Scope))
+ then
+ E_Scope := Scope (E_Scope);
- Build_DIC_Procedure_Body (E);
+ elsif Ekind (E_Scope) = E_Subprogram_Body then
+ E_Scope := Corresponding_Spec (Unit_Declaration_Node (E_Scope));
end if;
- end Expand_SPARK_N_Freeze_Type;
+
+ -- If the scope of the entity is in open scopes, it is the current one
+ -- or an enclosing one, including a loop, a block, or a subprogram.
+
+ if In_Open_Scopes (E_Scope) then
+ In_Other_Scope := False;
+ In_Outer_Scope := E_Scope /= Current_Scope;
+
+ -- Otherwise it is a local package or a different compilation unit
+
+ else
+ In_Other_Scope := True;
+ In_Outer_Scope := False;
+ end if;
+
+ -- If the entity being frozen is defined in a scope that is not
+ -- currently on the scope stack, we must establish the proper
+ -- visibility before freezing the entity and related subprograms.
+
+ if In_Other_Scope then
+ Push_Scope (E_Scope);
+
+ -- Finalizers are little odd in terms of freezing. The spec of the
+ -- procedure appears in the declarations while the body appears in
+ -- the statement part of a single construct. Since the finalizer must
+ -- be called by the At_End handler of the construct, the spec is
+ -- manually frozen right after its declaration. The only side effect
+ -- of this action appears in contexts where the construct is not in
+ -- its final resting place. These contexts are:
+
+ -- * Entry bodies - The declarations and statements are moved to
+ -- the procedure equivalen of the entry.
+ -- * Protected subprograms - The declarations and statements are
+ -- moved to the non-protected version of the subprogram.
+ -- * Task bodies - The declarations and statements are moved to the
+ -- task body procedure.
+ -- * Blocks that will be rewritten as subprograms when unnesting
+ -- is in effect.
+
+ -- Visible declarations do not need to be installed in these three
+ -- cases since it does not make semantic sense to do so. All entities
+ -- referenced by a finalizer are visible and already resolved, plus
+ -- the enclosing scope may not have visible declarations at all.
+
+ if Ekind (E) = E_Procedure
+ and then Is_Finalizer (E)
+ and then
+ (Is_Entry (E_Scope)
+ or else (Is_Subprogram (E_Scope)
+ and then Is_Protected_Type (Scope (E_Scope)))
+ or else Is_Task_Type (E_Scope)
+ or else Ekind (E_Scope) = E_Block)
+ then
+ null;
+ else
+ Install_Visible_Declarations (E_Scope);
+ end if;
+
+ if Is_Concurrent_Type (E_Scope)
+ or else Is_Package_Or_Generic_Package (E_Scope)
+ then
+ Install_Private_Declarations (E_Scope);
+ end if;
+
+ -- If the entity is in an outer scope, then that scope needs to
+ -- temporarily become the current scope so that operations created
+ -- during type freezing will be declared in the right scope and
+ -- can properly override any corresponding inherited operations.
+
+ elsif In_Outer_Scope then
+ Push_Scope (E_Scope);
+ end if;
+
+ -- Remember that we are processing a freezing entity and its freezing
+ -- nodes. This flag (non-zero = set) is used to avoid the need of
+ -- climbing through the tree while processing the freezing actions (ie.
+ -- to avoid generating spurious warnings or to avoid killing constant
+ -- indications while processing the code associated with freezing
+ -- actions). We use a counter to deal with nesting.
+
+ Inside_Freezing_Actions := Inside_Freezing_Actions + 1;
+
+ -- Currently only types require freezing in SPARK
+
+ SPARK_Freeze_Type (N);
+
+ -- Analyze actions in freeze node, if any
+
+ Action := First (Actions (N));
+ while Present (Action) loop
+ Analyze (Action);
+ Next (Action);
+ end loop;
+
+ -- Pop scope if we installed one for the analysis
+
+ if In_Other_Scope then
+ if Ekind (Current_Scope) = E_Package then
+ End_Package_Scope (E_Scope);
+ else
+ End_Scope;
+ end if;
+
+ elsif In_Outer_Scope then
+ Pop_Scope;
+ end if;
+
+ -- Restore previous value of the nesting-level counter that records
+ -- whether we are inside a (possibly nested) call to this procedure.
+
+ Inside_Freezing_Actions := Inside_Freezing_Actions - 1;
+ end Expand_SPARK_N_Freeze_Entity;
----------------------------------------
-- Expand_SPARK_N_Attribute_Reference --
@@ -705,4 +885,83 @@ package body Exp_SPARK is
end if;
end Expand_SPARK_Potential_Renaming;
+ -----------------------
+ -- SPARK_Freeze_Type --
+ -----------------------
+
+ procedure SPARK_Freeze_Type (N : Entity_Id) is
+ Typ : constant Entity_Id := Entity (N);
+
+ Renamed_Eq : Node_Id;
+ -- Defining unit name for the predefined equality function in the case
+ -- where the type has a primitive operation that is a renaming of
+ -- predefined equality (but only if there is also an overriding
+ -- user-defined equality function). Used to pass this entity from
+ -- Make_Predefined_Primitive_Specs to Predefined_Primitive_Bodies.
+
+ Decl : Node_Id;
+ Eq_Spec : Node_Id := Empty;
+ Predef_List : List_Id;
+
+ Saved_GM : constant Ghost_Mode_Type := Ghost_Mode;
+ Saved_IGR : constant Node_Id := Ignored_Ghost_Region;
+ -- Save the Ghost-related attributes to restore on exit
+
+ begin
+ -- The type being frozen may be subject to pragma Ghost. Set the mode
+ -- now to ensure that any nodes generated during freezing are properly
+ -- marked as Ghost.
+
+ Set_Ghost_Mode (Typ);
+
+ -- When a DIC is inherited by a tagged type, it may need to be
+ -- specialized to the descendant type, hence build a separate DIC
+ -- procedure for it as done during regular expansion for compilation.
+
+ if Has_DIC (Typ) and then Is_Tagged_Type (Typ) then
+ -- Why is this needed for DIC, but not for other aspects (such as
+ -- Type_Invariant)???
+
+ Build_DIC_Procedure_Body (Typ);
+ end if;
+
+ if Ekind (Typ) = E_Record_Type
+ and then Is_Tagged_Type (Typ)
+ and then not Is_Interface (Typ)
+ and then not Is_Limited_Type (Typ)
+ then
+ if Is_CPP_Class (Root_Type (Typ))
+ and then Convention (Typ) = Convention_CPP
+ then
+ null;
+
+ -- Do not add the spec of the predefined primitives if we are
+ -- compiling under restriction No_Dispatching_Calls.
+
+ elsif not Restriction_Active (No_Dispatching_Calls) then
+ Set_Is_Frozen (Typ, False);
+
+ Predef_List := New_List;
+ Exp_Ch3.Make_Predefined_Primitive_Eq_Spec
+ (Typ, Predef_List, Renamed_Eq);
+ Eq_Spec := First (Predef_List);
+ Insert_List_Before_And_Analyze (N, Predef_List);
+
+ Set_Is_Frozen (Typ);
+
+ -- Remove link from the parent list to the spec and body of
+ -- the dispatching equality, but keep the link in the opposite
+ -- direction, to allow up-traversal of the AST.
+
+ if Present (Eq_Spec) then
+ Decl := Parent (Eq_Spec);
+ Remove (Eq_Spec);
+ Set_Parent (Eq_Spec, Decl);
+ end if;
+ end if;
+ end if;
+
+ Restore_Ghost_Region (Saved_GM, Saved_IGR);
+ end SPARK_Freeze_Type;
+
end Exp_SPARK;
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2021-12-02 16:29 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-12-02 16:29 [gcc r12-5733] [Ada] Enable expansion of dispatching equality for GNATprove Pierre-Marie de Rodat
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).