aboutsummaryrefslogtreecommitdiff
path: root/gcc/ada/sem_ch3.adb
diff options
context:
space:
mode:
authorJavier Miranda <miranda@adacore.com>2024-09-30 09:08:04 +0000
committerMarc Poulhiès <dkm@gcc.gnu.org>2024-10-25 11:09:02 +0200
commit13a4eb2548a9907fd5c57c1e4b51b22411066cf0 (patch)
treeb72721fcc9834cbf61f85ae32e47201ea170da36 /gcc/ada/sem_ch3.adb
parent257d0d7769c29639c8bd07c986e36283f0a0ab8a (diff)
downloadgcc-13a4eb2548a9907fd5c57c1e4b51b22411066cf0.zip
gcc-13a4eb2548a9907fd5c57c1e4b51b22411066cf0.tar.gz
gcc-13a4eb2548a9907fd5c57c1e4b51b22411066cf0.tar.bz2
ada: Pragma Pre_Class and Post_Class have no effect at runtime
The pragmas Pre_Class and Post_Class are accepted by the compiler but have no effect at runtime. gcc/ada/ChangeLog: * freeze.adb (Freeze_Entity): If the entity is an access-to-subprogram type declaration that pre/postcondition contracts, build the wrapper (if not previously done as part of processing aspects). * sem_ch3.adb (Build_Access_Subprogram_Wrapper): Add missing support for building the wrapper when the access type has pragmas Pre_Class/Post_Class. (Build_Access_Subprogram_Wrapper_Declaration): New subprogram. * sem_ch3.ads (Build_Access_Subprogram_Wrapper): Spec moved to the public part of the package. * sem_prag.adb (Analyze_Pre_Post_Condition): Store in the tree copy of class-wide pre/postcondition expression; required to merge it with inherited conditions. (Is_Valid_Assertion_Kind): Added Pre_Class and Post_Class.
Diffstat (limited to 'gcc/ada/sem_ch3.adb')
-rw-r--r--gcc/ada/sem_ch3.adb260
1 files changed, 178 insertions, 82 deletions
diff --git a/gcc/ada/sem_ch3.adb b/gcc/ada/sem_ch3.adb
index 00d5fe2..b684f69 100644
--- a/gcc/ada/sem_ch3.adb
+++ b/gcc/ada/sem_ch3.adb
@@ -105,11 +105,6 @@ package body Sem_Ch3 is
-- abstract interface types implemented by a record type or a derived
-- record type.
- procedure Build_Access_Subprogram_Wrapper (Decl : Node_Id);
- -- When an access-to-subprogram type has pre/postconditions, we build a
- -- subprogram that includes these contracts and is invoked by an indirect
- -- call through the corresponding access type.
-
procedure Build_Derived_Type
(N : Node_Id;
Parent_Type : Entity_Id;
@@ -6997,19 +6992,78 @@ package body Sem_Ch3 is
-------------------------------------
procedure Build_Access_Subprogram_Wrapper (Decl : Node_Id) is
- Loc : constant Source_Ptr := Sloc (Decl);
Id : constant Entity_Id := Defining_Identifier (Decl);
+ Loc : constant Source_Ptr := Sloc (Decl);
+ Subp : constant Entity_Id := Make_Temporary (Loc, 'A');
Type_Def : constant Node_Id := Type_Definition (Decl);
- Specs : constant List_Id :=
- Parameter_Specifications (Type_Def);
- Profile : constant List_Id := New_List;
- Subp : constant Entity_Id := Make_Temporary (Loc, 'A');
+ Specs : constant List_Id := Parameter_Specifications (Type_Def);
+
+ function Build_Access_Subprogram_Wrapper_Declaration return Node_Id;
+ -- Build the declaration and the specification of the wrapper
+
+ -------------------------------------------------
+ -- Build_Access_Subprogram_Wrapper_Declaration --
+ -------------------------------------------------
+
+ function Build_Access_Subprogram_Wrapper_Declaration return Node_Id is
+ Form_P : Node_Id;
+ New_Decl : Node_Id;
+ New_P : Node_Id;
+ Profile : constant List_Id := New_List;
+ Spec : Node_Id;
+
+ begin
+ Form_P := First (Specs);
+
+ while Present (Form_P) loop
+ New_P := New_Copy_Tree (Form_P);
+ Set_Defining_Identifier (New_P,
+ Make_Defining_Identifier
+ (Loc, Chars (Defining_Identifier (Form_P))));
+ Append (New_P, Profile);
+ Next (Form_P);
+ end loop;
+
+ -- Add to parameter specifications the access parameter that is
+ -- passed in from an indirect call.
+
+ Append (
+ Make_Parameter_Specification (Loc,
+ Defining_Identifier => Make_Temporary (Loc, 'P'),
+ Parameter_Type => New_Occurrence_Of (Id, Loc)),
+ Profile);
+
+ if Nkind (Type_Def) = N_Access_Procedure_Definition then
+ Spec :=
+ Make_Procedure_Specification (Loc,
+ Defining_Unit_Name => Subp,
+ Parameter_Specifications => Profile);
+ Mutate_Ekind (Subp, E_Procedure);
+ else
+ Spec :=
+ Make_Function_Specification (Loc,
+ Defining_Unit_Name => Subp,
+ Parameter_Specifications => Profile,
+ Result_Definition =>
+ New_Copy_Tree (Result_Definition (Type_Def)));
+ Mutate_Ekind (Subp, E_Function);
+ end if;
+
+ New_Decl :=
+ Make_Subprogram_Declaration (Loc, Specification => Spec);
+
+ Set_Is_Wrapper (Subp);
+
+ -- The wrapper is declared in the freezing actions to facilitate its
+ -- identification and thus avoid handling it as a primitive operation
+ -- of a tagged type (see Is_Access_To_Subprogram_Wrapper); otherwise
+ -- it may be handled as a dispatching operation and erroneously
+ -- registered in a dispatch table.
- Contracts : constant List_Id := New_List;
- Form_P : Node_Id;
- New_P : Node_Id;
- New_Decl : Node_Id;
- Spec : Node_Id;
+ Append_Freeze_Action (Id, New_Decl);
+
+ return New_Decl;
+ end Build_Access_Subprogram_Wrapper_Declaration;
procedure Replace_Type_Name (Expr : Node_Id);
-- In the expressions for contract aspects, replace occurrences of the
@@ -7041,6 +7095,17 @@ package body Sem_Ch3 is
Traverse (Expr);
end Replace_Type_Name;
+ -- Local variables
+
+ Has_Wrapper : constant Boolean :=
+ Present
+ (Access_Subprogram_Wrapper (Designated_Type (Id)));
+ Contracts : List_Id := No_List;
+ Wrapper_Decl : Node_Id;
+ Pragmas : List_Id := No_List;
+
+ -- Start of processing for Build_Access_Subprogram_Wrapper
+
begin
if Ekind (Id) in E_Access_Subprogram_Type
| E_Access_Protected_Subprogram_Type
@@ -7055,80 +7120,111 @@ package body Sem_Ch3 is
return;
end if;
- declare
- Asp : Node_Id;
- A_Id : Aspect_Id;
+ -- Current state: We are processing the full-type declaration of
+ -- this access-to-subprogram type. Collect its pre/postconditions
+ -- and replace occurrences of the access type with the name of the
+ -- subprogram entity.
- begin
- Asp := First (Aspect_Specifications (Decl));
- while Present (Asp) loop
- A_Id := Get_Aspect_Id (Chars (Identifier (Asp)));
- if A_Id = Aspect_Pre or else A_Id = Aspect_Post then
- Append (New_Copy_Tree (Asp), Contracts);
- Replace_Type_Name (Expression (Last (Contracts)));
- end if;
- Next (Asp);
- end loop;
- end;
+ if not Is_Frozen (Id) then
+ if Present (Aspect_Specifications (Decl)) then
+ declare
+ Asp : Node_Id;
+ A_Id : Aspect_Id;
+ New_Contract : Node_Id;
- -- If there are no contract aspects, no need for a wrapper.
+ begin
+ Asp := First (Aspect_Specifications (Decl));
+ while Present (Asp) loop
+ A_Id := Get_Aspect_Id (Chars (Identifier (Asp)));
+
+ if A_Id = Aspect_Pre or else A_Id = Aspect_Post then
+ New_Contract := New_Copy_Tree (Asp);
+ Append_New (New_Contract, Contracts);
+ Replace_Type_Name (Expression (New_Contract));
+ end if;
- if Is_Empty_List (Contracts) then
- return;
- end if;
+ Next (Asp);
+ end loop;
+ end;
+ end if;
- Form_P := First (Specs);
+ -- No wrapper is needed if there are no contract aspects
- while Present (Form_P) loop
- New_P := New_Copy_Tree (Form_P);
- Set_Defining_Identifier (New_P,
- Make_Defining_Identifier
- (Loc, Chars (Defining_Identifier (Form_P))));
- Append (New_P, Profile);
- Next (Form_P);
- end loop;
+ if Is_Empty_List (Contracts) then
+ return;
+ end if;
+
+ -- Build the wrapper declaration, propagate the aspects, and link
+ -- the wrapper with its access-type declaration.
+
+ Wrapper_Decl := Build_Access_Subprogram_Wrapper_Declaration;
+ Set_Aspect_Specifications (Wrapper_Decl, Contracts);
+ Set_Access_Subprogram_Wrapper (Designated_Type (Id), Subp);
+
+ -- Build the body of this wrapper
+
+ Build_Access_Subprogram_Wrapper_Body (Decl, Wrapper_Decl);
+
+ -- Current status: We are freezing the access-to-subprogram type entity.
+ -- Collect its pragmas pre/postconditions that come from the sources,
+ -- and replace occurrences of the access type with the name of the
+ -- subprogram entity.
- -- Add to parameter specifications the access parameter that is passed
- -- in from an indirect call.
-
- Append (
- Make_Parameter_Specification (Loc,
- Defining_Identifier => Make_Temporary (Loc, 'P'),
- Parameter_Type => New_Occurrence_Of (Id, Loc)),
- Profile);
-
- if Nkind (Type_Def) = N_Access_Procedure_Definition then
- Spec :=
- Make_Procedure_Specification (Loc,
- Defining_Unit_Name => Subp,
- Parameter_Specifications => Profile);
- Mutate_Ekind (Subp, E_Procedure);
else
- Spec :=
- Make_Function_Specification (Loc,
- Defining_Unit_Name => Subp,
- Parameter_Specifications => Profile,
- Result_Definition =>
- New_Copy_Tree
- (Result_Definition (Type_Definition (Decl))));
- Mutate_Ekind (Subp, E_Function);
- end if;
-
- New_Decl :=
- Make_Subprogram_Declaration (Loc, Specification => Spec);
- Set_Aspect_Specifications (New_Decl, Contracts);
- Set_Is_Wrapper (Subp);
-
- -- The wrapper is declared in the freezing actions to facilitate its
- -- identification and thus avoid handling it as a primitive operation
- -- of a tagged type (see Is_Access_To_Subprogram_Wrapper); otherwise it
- -- may be handled as a dispatching operation and erroneously registered
- -- in a dispatch table.
-
- Append_Freeze_Action (Id, New_Decl);
-
- Set_Access_Subprogram_Wrapper (Designated_Type (Id), Subp);
- Build_Access_Subprogram_Wrapper_Body (Decl, New_Decl);
+ if Present (Contract (Designated_Type (Id))) then
+ declare
+ Prag : Node_Id;
+ New_Pragma : Node_Id;
+
+ begin
+ Prag := Pre_Post_Conditions (Contract (Designated_Type (Id)));
+
+ while Present (Prag) loop
+ if Comes_From_Source (Prag) then
+ New_Pragma := New_Copy_Tree (Prag);
+ Append_New (New_Pragma, Pragmas);
+ Replace_Type_Name
+ (First (Pragma_Argument_Associations (New_Pragma)));
+
+ -- Force reanalyzing the copy since it will be applied to
+ -- the wrapper.
+
+ Set_Analyzed (New_Pragma, False);
+ end if;
+
+ Prag := Next_Pragma (Prag);
+ end loop;
+ end;
+
+ -- No wrapper is needed if there are no pre/postcondition pragmas
+
+ if Is_Empty_List (Pragmas) then
+ return;
+ end if;
+
+ -- Build the wrapper, if not previously done, and propagate the
+ -- pragmas to the wrapper spec. The access-to-subprogram type
+ -- declaration might have a precondition aspect and a
+ -- postcondition pragma, or vice versa. In such cases,
+ -- Build_Access_Subprogram_Wrapper is called twice: (1) when
+ -- processing the full-type declaration (building the wrapper
+ -- with the aspect), and (2) when freezing the type (adding the
+ -- pragmas after the spec of the wrapper).
+
+ if not Has_Wrapper then
+ Wrapper_Decl := Build_Access_Subprogram_Wrapper_Declaration;
+ Insert_List_After (Wrapper_Decl, Pragmas);
+
+ Set_Access_Subprogram_Wrapper (Designated_Type (Id), Subp);
+ Build_Access_Subprogram_Wrapper_Body (Decl, Wrapper_Decl);
+ else
+ Wrapper_Decl :=
+ Parent
+ (Parent (Access_Subprogram_Wrapper (Designated_Type (Id))));
+ Insert_List_After (Wrapper_Decl, Pragmas);
+ end if;
+ end if;
+ end if;
end Build_Access_Subprogram_Wrapper;
-------------------------------