aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Botcazou <ebotcazou@adacore.com>2020-03-20 23:00:32 +0100
committerPierre-Marie de Rodat <derodat@adacore.com>2020-06-12 04:29:15 -0400
commitec772e4b269206a943b3caa5544d9c7ac1d8de1a (patch)
tree2e4f88df493177cf8b9d464d87e8045c9450b5b3
parent6f6f89a494e3b9b2d9ed73589f04b54c3282a5ef (diff)
downloadgcc-ec772e4b269206a943b3caa5544d9c7ac1d8de1a.zip
gcc-ec772e4b269206a943b3caa5544d9c7ac1d8de1a.tar.gz
gcc-ec772e4b269206a943b3caa5544d9c7ac1d8de1a.tar.bz2
[Ada] Implement AI12-0175 Preelaborable packages with address clauses
2020-06-12 Eric Botcazou <ebotcazou@adacore.com> gcc/ada/ * rtsfind.ads (RTU_Id): Add System_Address_To_Access_Conversions. * sem_elab.adb (Elaboration_Phase_Active): Alphabetize. (Finalize_All_Data_Structures): Likewise. (Error_Preelaborated_Call): New procedure. (Build_Call_Marker): Set Is_Preelaborable_Call flag in marker. (Build_Access_Marker): Likewise. (Build_Subprogram_Invocation): Likewise. (Build_Task_Activation): Likewise. (Check_Preelaborated_Call): Return when the call is preelaborable. Call Error_Preelaborated_Call to give the error otherwise. (Check_Elab_Call): Likewise. * sem_util.adb (Is_Preelaborable_Function): New predicate. (Is_Non_Preelaborable_Construct.Visit): Recurse on the Explicit_Actual_Parameter field of N_Parameter_Association. (Is_Non_Preelaborable_Construct.Visit_Subexpression): In Ada 2020, for a call to a preelaborable function, visit the parameter list; otherwise, raise Non_Preelaborable exception. (Is_Preelaborable_Construct): Likewise, but recursively check the parameters instead and return false upon failure, otherwise true. * sinfo.ads (Is_Preelaborable_Call): New flag in call marker nodes. (Is_Preelaborable_Call): New inline function. (Set_Is_Preelaborable_Call): New inline procedure. * sinfo.adb (Is_Preelaborable_Call): New inline function. (Set_Is_Preelaborable_Call): New inline procedure.
-rw-r--r--gcc/ada/rtsfind.ads1
-rw-r--r--gcc/ada/sem_elab.adb80
-rw-r--r--gcc/ada/sem_util.adb90
-rw-r--r--gcc/ada/sinfo.adb16
-rw-r--r--gcc/ada/sinfo.ads13
5 files changed, 181 insertions, 19 deletions
diff --git a/gcc/ada/rtsfind.ads b/gcc/ada/rtsfind.ads
index df98023..ad113fd 100644
--- a/gcc/ada/rtsfind.ads
+++ b/gcc/ada/rtsfind.ads
@@ -173,6 +173,7 @@ package Rtsfind is
-- Children of System
System_Address_Image,
+ System_Address_To_Access_Conversions,
System_Arith_64,
System_AST_Handling,
System_Assertions,
diff --git a/gcc/ada/sem_elab.adb b/gcc/ada/sem_elab.adb
index 0fa3d14..8aa1ca7 100644
--- a/gcc/ada/sem_elab.adb
+++ b/gcc/ada/sem_elab.adb
@@ -1952,6 +1952,18 @@ package body Sem_Elab is
pragma Inline (Compilation_Unit);
-- Return the N_Compilation_Unit node of unit Unit_Id
+ function Elaboration_Phase_Active return Boolean;
+ pragma Inline (Elaboration_Phase_Active);
+ -- Determine whether the elaboration phase of the compilation has started
+
+ procedure Error_Preelaborated_Call (N : Node_Id);
+ -- Give an error or warning for a non-static/non-preelaborable call in a
+ -- preelaborated unit.
+
+ procedure Finalize_All_Data_Structures;
+ pragma Inline (Finalize_All_Data_Structures);
+ -- Destroy all internal data structures
+
function Find_Enclosing_Instance (N : Node_Id) return Node_Id;
pragma Inline (Find_Enclosing_Instance);
-- Find the declaration or body of the nearest expanded instance which
@@ -1972,14 +1984,6 @@ package body Sem_Elab is
-- Return the type of subprogram Subp_Id's first formal parameter. If the
-- subprogram lacks formal parameters, return Empty.
- function Elaboration_Phase_Active return Boolean;
- pragma Inline (Elaboration_Phase_Active);
- -- Determine whether the elaboration phase of the compilation has started
-
- procedure Finalize_All_Data_Structures;
- pragma Inline (Finalize_All_Data_Structures);
- -- Destroy all internal data structures
-
function Has_Body (Pack_Decl : Node_Id) return Boolean;
pragma Inline (Has_Body);
-- Determine whether package declaration Pack_Decl has a corresponding body
@@ -3745,6 +3749,15 @@ package body Sem_Elab is
Set_Is_SPARK_Mode_On_Node (Marker, Is_SPARK_Mode_On_Node (N));
Set_Target (Marker, Subp_Id);
+ -- Ada 2020 (AI12-0175): Calls to certain functions that are essentially
+ -- unchecked conversions are preelaborable.
+
+ if Ada_Version >= Ada_2020 then
+ Set_Is_Preelaborable_Call (Marker, Is_Preelaborable_Construct (N));
+ else
+ Set_Is_Preelaborable_Call (Marker, False);
+ end if;
+
-- The marker is inserted prior to the original call. This placement has
-- several desirable effects:
@@ -4878,6 +4891,8 @@ package body Sem_Elab is
(Marker, Elaboration_Checks_OK (Attr_Rep));
Set_Is_Elaboration_Warnings_OK_Node
(Marker, Elaboration_Warnings_OK (Attr_Rep));
+ Set_Is_Preelaborable_Call
+ (Marker, False);
Set_Is_Source_Call
(Marker, Comes_From_Source (Attr));
Set_Is_SPARK_Mode_On_Node
@@ -8838,6 +8853,29 @@ package body Sem_Elab is
return Elaboration_Phase = Active;
end Elaboration_Phase_Active;
+ ------------------------------
+ -- Error_Preelaborated_Call --
+ ------------------------------
+
+ procedure Error_Preelaborated_Call (N : Node_Id) is
+ begin
+ -- This is a warning in GNAT mode allowing such calls to be used in the
+ -- predefined library units with appropriate care.
+
+ Error_Msg_Warn := GNAT_Mode;
+
+ -- Ada 2020 (AI12-0175): Calls to certain functions that are essentially
+ -- unchecked conversions are preelaborable.
+
+ if Ada_Version >= Ada_2020 then
+ Error_Msg_N
+ ("<<non-preelaborable call not allowed in preelaborated unit", N);
+ else
+ Error_Msg_N
+ ("<<non-static call not allowed in preelaborated unit", N);
+ end if;
+ end Error_Preelaborated_Call;
+
----------------------------------
-- Finalize_All_Data_Structures --
----------------------------------
@@ -11894,6 +11932,7 @@ package body Sem_Elab is
Set_Is_Elaboration_Checks_OK_Node (Marker, False);
Set_Is_Elaboration_Warnings_OK_Node (Marker, False);
Set_Is_Ignored_Ghost_Node (Marker, False);
+ Set_Is_Preelaborable_Call (Marker, False);
Set_Is_Source_Call (Marker, False);
Set_Is_SPARK_Mode_On_Node (Marker, False);
@@ -11933,6 +11972,7 @@ package body Sem_Elab is
Set_Is_Elaboration_Checks_OK_Node (Marker, False);
Set_Is_Elaboration_Warnings_OK_Node (Marker, False);
Set_Is_Ignored_Ghost_Node (Marker, False);
+ Set_Is_Preelaborable_Call (Marker, False);
Set_Is_Source_Call (Marker, False);
Set_Is_SPARK_Mode_On_Node (Marker, False);
@@ -13758,6 +13798,11 @@ package body Sem_Elab is
if not Is_Source_Call (Call) then
return;
+ -- Nothing to do when the call is preelaborable by definition
+
+ elsif Is_Preelaborable_Call (Call) then
+ return;
+
-- Library-level calls are always considered because they are part of
-- the associated unit's elaboration actions.
@@ -13779,13 +13824,10 @@ package body Sem_Elab is
return;
end if;
- -- The call appears within a preelaborated unit. Emit a warning only
- -- for internal uses, otherwise this is an error.
+ -- If the call appears within a preelaborated unit, give an error
if In_Preelaborated_Context (Call) then
- Error_Msg_Warn := GNAT_Mode;
- Error_Msg_N
- ("<<non-static call not allowed in preelaborated unit", Call);
+ Error_Preelaborated_Call (Call);
end if;
end Check_Preelaborated_Call;
@@ -17506,17 +17548,17 @@ package body Sem_Elab is
-- Complain if ref that comes from source in preelaborated unit
-- and we are not inside a subprogram (i.e. we are in elab code).
+ -- Ada 2020 (AI12-0175): Calls to certain functions that are
+ -- essentially unchecked conversions are preelaborable.
+
if Comes_From_Source (N)
and then In_Preelaborated_Unit
and then not In_Inlined_Body
and then Nkind (N) /= N_Attribute_Reference
+ and then not (Ada_Version >= Ada_2020
+ and then Is_Preelaborable_Construct (N))
then
- -- This is a warning in GNAT mode allowing such calls to be
- -- used in the predefined library with appropriate care.
-
- Error_Msg_Warn := GNAT_Mode;
- Error_Msg_N
- ("<<non-static call not allowed in preelaborated unit", N);
+ Error_Preelaborated_Call (N);
return;
end if;
diff --git a/gcc/ada/sem_util.adb b/gcc/ada/sem_util.adb
index 948ee60..0a62b10 100644
--- a/gcc/ada/sem_util.adb
+++ b/gcc/ada/sem_util.adb
@@ -133,6 +133,10 @@ package body Sem_Util is
-- components in the selected variant to determine whether all of them
-- have a default.
+ function Is_Preelaborable_Function (Id : Entity_Id) return Boolean;
+ -- Ada 2020: Determine whether the specified function is suitable as the
+ -- name of a call in a preelaborable construct (RM 10.2.1(7/5)).
+
type Null_Status_Kind is
(Is_Null,
-- This value indicates that a subexpression is known to have a null
@@ -16485,6 +16489,9 @@ package body Sem_Util is
Visit (Discrete_Subtype_Definition (Nod));
+ when N_Parameter_Association =>
+ Visit (Explicit_Actual_Parameter (N));
+
when N_Protected_Definition =>
-- End_Label is left out because it is not relevant for
@@ -16650,6 +16657,21 @@ package body Sem_Util is
Visit_List (Actions (Expr));
Visit (Expression (Expr));
+ when N_Function_Call =>
+
+ -- Ada 2020 (AI12-0175): Calls to certain functions that are
+ -- essentially unchecked conversions are preelaborable.
+
+ if Ada_Version >= Ada_2020
+ and then Nkind (Expr) = N_Function_Call
+ and then Is_Entity_Name (Name (Expr))
+ and then Is_Preelaborable_Function (Entity (Name (Expr)))
+ then
+ Visit_List (Parameter_Associations (Expr));
+ else
+ raise Non_Preelaborable;
+ end if;
+
when N_If_Expression =>
Visit_List (Expressions (Expr));
@@ -17781,6 +17803,30 @@ package body Sem_Util is
elsif Nkind (N) = N_Null then
return True;
+ -- Ada 2020 (AI12-0175): Calls to certain functions that are essentially
+ -- unchecked conversions are preelaborable.
+
+ elsif Ada_Version >= Ada_2020
+ and then Nkind (N) = N_Function_Call
+ and then Is_Entity_Name (Name (N))
+ and then Is_Preelaborable_Function (Entity (Name (N)))
+ then
+ declare
+ A : Node_Id;
+ begin
+ A := First_Actual (N);
+
+ while Present (A) loop
+ if not Is_Preelaborable_Construct (A) then
+ return False;
+ end if;
+
+ Next_Actual (A);
+ end loop;
+ end;
+
+ return True;
+
-- Otherwise the construct is not preelaborable
else
@@ -17788,6 +17834,50 @@ package body Sem_Util is
end if;
end Is_Preelaborable_Construct;
+ -------------------------------
+ -- Is_Preelaborable_Function --
+ -------------------------------
+
+ function Is_Preelaborable_Function (Id : Entity_Id) return Boolean is
+ SATAC : constant Rtsfind.RTU_Id := System_Address_To_Access_Conversions;
+ Scop : constant Entity_Id := Scope (Id);
+
+ begin
+ -- Small optimization: every allowed function has convention Intrinsic
+ -- (see Analyze_Subprogram_Instantiation for the subtlety in the test).
+
+ if not Is_Intrinsic_Subprogram (Id)
+ and then Convention (Id) /= Convention_Intrinsic
+ then
+ return False;
+ end if;
+
+ -- An instance of Unchecked_Conversion
+
+ if Is_Unchecked_Conversion_Instance (Id) then
+ return True;
+ end if;
+
+ -- A function declared in System.Storage_Elements
+
+ if Is_RTU (Scop, System_Storage_Elements) then
+ return True;
+ end if;
+
+ -- The functions To_Pointer and To_Address declared in an instance of
+ -- System.Address_To_Access_Conversions (they are the only ones).
+
+ if Ekind (Scop) = E_Package
+ and then Nkind (Parent (Scop)) = N_Package_Specification
+ and then Present (Generic_Parent (Parent (Scop)))
+ and then Is_RTU (Generic_Parent (Parent (Scop)), SATAC)
+ then
+ return True;
+ end if;
+
+ return False;
+ end Is_Preelaborable_Function;
+
---------------------------------
-- Is_Protected_Self_Reference --
---------------------------------
diff --git a/gcc/ada/sinfo.adb b/gcc/ada/sinfo.adb
index f6e70c1..642e859 100644
--- a/gcc/ada/sinfo.adb
+++ b/gcc/ada/sinfo.adb
@@ -2096,6 +2096,14 @@ package body Sinfo is
return Flag13 (N);
end Is_Power_Of_2_For_Shift;
+ function Is_Preelaborable_Call
+ (N : Node_Id) return Boolean is
+ begin
+ pragma Assert (False
+ or else NT (N).Nkind = N_Call_Marker);
+ return Flag7 (N);
+ end Is_Preelaborable_Call;
+
function Is_Prefixed_Call
(N : Node_Id) return Boolean is
begin
@@ -5563,6 +5571,14 @@ package body Sinfo is
Set_Flag13 (N, Val);
end Set_Is_Power_Of_2_For_Shift;
+ procedure Set_Is_Preelaborable_Call
+ (N : Node_Id; Val : Boolean := True) is
+ begin
+ pragma Assert (False
+ or else NT (N).Nkind = N_Call_Marker);
+ Set_Flag7 (N, Val);
+ end Set_Is_Preelaborable_Call;
+
procedure Set_Is_Prefixed_Call
(N : Node_Id; Val : Boolean := True) is
begin
diff --git a/gcc/ada/sinfo.ads b/gcc/ada/sinfo.ads
index ea4f8ed..d0739b8 100644
--- a/gcc/ada/sinfo.ads
+++ b/gcc/ada/sinfo.ads
@@ -1849,6 +1849,10 @@ package Sinfo is
-- conditions holds, and the flag is set, then the division or
-- multiplication can be (and is) converted to a shift.
+ -- Is_Preelaborable_Call (Flag7-Sem)
+ -- Present in call marker nodes. Set when the related call is non-static
+ -- but preelaborable.
+
-- Is_Prefixed_Call (Flag17-Sem)
-- This flag is set in a selected component within a generic unit, if
-- it resolves to a prefixed call to a primitive operation. The flag
@@ -7830,6 +7834,7 @@ package Sinfo is
-- Is_Source_Call (Flag4-Sem)
-- Is_Declaration_Level_Node (Flag5-Sem)
-- Is_Dispatching_Call (Flag6-Sem)
+ -- Is_Preelaborable_Call (Flag7-Sem)
-- Is_Known_Guaranteed_ABE (Flag18-Sem)
------------------------
@@ -9767,6 +9772,9 @@ package Sinfo is
function Is_Power_Of_2_For_Shift
(N : Node_Id) return Boolean; -- Flag13
+ function Is_Preelaborable_Call
+ (N : Node_Id) return Boolean; -- Flag7
+
function Is_Prefixed_Call
(N : Node_Id) return Boolean; -- Flag17
@@ -10870,6 +10878,9 @@ package Sinfo is
procedure Set_Is_Power_Of_2_For_Shift
(N : Node_Id; Val : Boolean := True); -- Flag13
+ procedure Set_Is_Preelaborable_Call
+ (N : Node_Id; Val : Boolean := True); -- Flag7
+
procedure Set_Is_Prefixed_Call
(N : Node_Id; Val : Boolean := True); -- Flag17
@@ -13395,6 +13406,7 @@ package Sinfo is
pragma Inline (Is_Null_Loop);
pragma Inline (Is_Overloaded);
pragma Inline (Is_Power_Of_2_For_Shift);
+ pragma Inline (Is_Preelaborable_Call);
pragma Inline (Is_Prefixed_Call);
pragma Inline (Is_Protected_Subprogram_Body);
pragma Inline (Is_Qualified_Universal_Literal);
@@ -13758,6 +13770,7 @@ package Sinfo is
pragma Inline (Set_Is_Null_Loop);
pragma Inline (Set_Is_Overloaded);
pragma Inline (Set_Is_Power_Of_2_For_Shift);
+ pragma Inline (Set_Is_Preelaborable_Call);
pragma Inline (Set_Is_Prefixed_Call);
pragma Inline (Set_Is_Protected_Subprogram_Body);
pragma Inline (Set_Is_Qualified_Universal_Literal);