Commit eaf51442 by Justin Squirek Committed by Pierre-Marie de Rodat

[Ada] No error on misplaced pragma Pure_Function

This patch fixes an issue whereby placement of the pragma/aspect Pure_Function
was not verified to have been in the same declarative part as the function
declaration incorrectly allowing it to appear after a function body or in a
different region like a private section.

2018-05-22  Justin Squirek  <squirek@adacore.com>

gcc/ada/

	* sem_ch12.adb (In_Same_Declarative_Part): Moved to sem_util.
	(Freeze_Subprogram_Body, Install_Body): Modify calls to
	In_Same_Declarative_Part.
	* sem_prag.adb (Analyze_Pragma-Pragma_Pure_Function): Add check to
	verify pragma declaration is within the same declarative list with
	corresponding error message.
	* sem_util.adb, sem_util.ads (In_Same_Declarative_Part): Moved from
	sem_ch12.adb and generalized to be useful outside the scope of
	freezing.

gcc/testsuite/

	* gnat.dg/pure_function1.adb, gnat.dg/pure_function1.ads,
	gnat.dg/pure_function2.adb, gnat.dg/pure_function2.ads: New testcases.

From-SVN: r260507
parent 80f0c69c
2018-05-22 Justin Squirek <squirek@adacore.com>
* sem_ch12.adb (In_Same_Declarative_Part): Moved to sem_util.
(Freeze_Subprogram_Body, Install_Body): Modify calls to
In_Same_Declarative_Part.
* sem_prag.adb (Analyze_Pragma-Pragma_Pure_Function): Add check to
verify pragma declaration is within the same declarative list with
corresponding error message.
* sem_util.adb, sem_util.ads (In_Same_Declarative_Part): Moved from
sem_ch12.adb and generalized to be useful outside the scope of
freezing.
2018-05-22 Hristian Kirtchev <kirtchev@adacore.com> 2018-05-22 Hristian Kirtchev <kirtchev@adacore.com>
* sem_ch6.adb (Analyze_Subprogram_Declaration): Set the proper * sem_ch6.adb (Analyze_Subprogram_Declaration): Set the proper
......
...@@ -657,17 +657,6 @@ package body Sem_Ch12 is ...@@ -657,17 +657,6 @@ package body Sem_Ch12 is
-- not done for the instantiation of the bodies, which only require the -- not done for the instantiation of the bodies, which only require the
-- instances of the generic parents to be in scope. -- instances of the generic parents to be in scope.
function In_Same_Declarative_Part
(F_Node : Node_Id;
Inst : Node_Id) return Boolean;
-- True if the instantiation Inst and the given freeze_node F_Node appear
-- within the same declarative part, ignoring subunits, but with no inter-
-- vening subprograms or concurrent units. Used to find the proper plave
-- for the freeze node of an instance, when the generic is declared in a
-- previous instance. If predicate is true, the freeze node of the instance
-- can be placed after the freeze node of the previous instance, Otherwise
-- it has to be placed at the end of the current declarative part.
function In_Main_Context (E : Entity_Id) return Boolean; function In_Main_Context (E : Entity_Id) return Boolean;
-- Check whether an instantiation is in the context of the main unit. -- Check whether an instantiation is in the context of the main unit.
-- Used to determine whether its body should be elaborated to allow -- Used to determine whether its body should be elaborated to allow
...@@ -8664,7 +8653,8 @@ package body Sem_Ch12 is ...@@ -8664,7 +8653,8 @@ package body Sem_Ch12 is
if Is_Generic_Instance (Par) if Is_Generic_Instance (Par)
and then Present (Freeze_Node (Par)) and then Present (Freeze_Node (Par))
and then In_Same_Declarative_Part (Freeze_Node (Par), Inst_Node) and then In_Same_Declarative_Part
(Parent (Freeze_Node (Par)), Inst_Node)
then then
-- The parent was a premature instantiation. Insert freeze node at -- The parent was a premature instantiation. Insert freeze node at
-- the end the current declarative part. -- the end the current declarative part.
...@@ -8711,11 +8701,11 @@ package body Sem_Ch12 is ...@@ -8711,11 +8701,11 @@ package body Sem_Ch12 is
and then Present (Freeze_Node (Par)) and then Present (Freeze_Node (Par))
and then Present (Enc_I) and then Present (Enc_I)
then then
if In_Same_Declarative_Part (Freeze_Node (Par), Enc_I) if In_Same_Declarative_Part (Parent (Freeze_Node (Par)), Enc_I)
or else or else
(Nkind (Enc_I) = N_Package_Body (Nkind (Enc_I) = N_Package_Body
and then and then In_Same_Declarative_Part
In_Same_Declarative_Part (Freeze_Node (Par), Parent (Enc_I))) (Parent (Freeze_Node (Par)), Parent (Enc_I)))
then then
-- The enclosing package may contain several instances. Rather -- The enclosing package may contain several instances. Rather
-- than computing the earliest point at which to insert its freeze -- than computing the earliest point at which to insert its freeze
...@@ -8985,46 +8975,6 @@ package body Sem_Ch12 is ...@@ -8985,46 +8975,6 @@ package body Sem_Ch12 is
(Current_Scope, Current_Scope, Assoc_Null); (Current_Scope, Current_Scope, Assoc_Null);
end Init_Env; end Init_Env;
------------------------------
-- In_Same_Declarative_Part --
------------------------------
function In_Same_Declarative_Part
(F_Node : Node_Id;
Inst : Node_Id) return Boolean
is
Decls : constant Node_Id := Parent (F_Node);
Nod : Node_Id;
begin
Nod := Parent (Inst);
while Present (Nod) loop
if Nod = Decls then
return True;
elsif Nkind_In (Nod, N_Subprogram_Body,
N_Package_Body,
N_Package_Declaration,
N_Task_Body,
N_Protected_Body,
N_Block_Statement)
then
return False;
elsif Nkind (Nod) = N_Subunit then
Nod := Corresponding_Stub (Nod);
elsif Nkind (Nod) = N_Compilation_Unit then
return False;
else
Nod := Parent (Nod);
end if;
end loop;
return False;
end In_Same_Declarative_Part;
--------------------- ---------------------
-- In_Main_Context -- -- In_Main_Context --
--------------------- ---------------------
...@@ -9536,7 +9486,7 @@ package body Sem_Ch12 is ...@@ -9536,7 +9486,7 @@ package body Sem_Ch12 is
-- Freeze instance of inner generic after instance of enclosing -- Freeze instance of inner generic after instance of enclosing
-- generic. -- generic.
if In_Same_Declarative_Part (Freeze_Node (Par), N) then if In_Same_Declarative_Part (Parent (Freeze_Node (Par)), N) then
-- Handle the following case: -- Handle the following case:
...@@ -9570,7 +9520,8 @@ package body Sem_Ch12 is ...@@ -9570,7 +9520,8 @@ package body Sem_Ch12 is
-- instance of enclosing generic. -- instance of enclosing generic.
elsif Nkind_In (Parent (N), N_Package_Body, N_Subprogram_Body) elsif Nkind_In (Parent (N), N_Package_Body, N_Subprogram_Body)
and then In_Same_Declarative_Part (Freeze_Node (Par), Parent (N)) and then In_Same_Declarative_Part
(Parent (Freeze_Node (Par)), Parent (N))
then then
declare declare
Enclosing : Entity_Id; Enclosing : Entity_Id;
......
...@@ -21043,6 +21043,8 @@ package body Sem_Prag is ...@@ -21043,6 +21043,8 @@ package body Sem_Prag is
E : Entity_Id; E : Entity_Id;
E_Id : Node_Id; E_Id : Node_Id;
Effective : Boolean := False; Effective : Boolean := False;
Orig_Def : Entity_Id;
Same_Decl : Boolean := False;
begin begin
GNAT_Pragma; GNAT_Pragma;
...@@ -21076,12 +21078,28 @@ package body Sem_Prag is ...@@ -21076,12 +21078,28 @@ package body Sem_Prag is
("pragma% requires a function name", Arg1); ("pragma% requires a function name", Arg1);
end if; end if;
-- When we have a generic function we must jump up a level
-- to the declaration of the wrapper package itself.
Orig_Def := Def_Id;
if Is_Generic_Instance (Def_Id) then
while Nkind (Orig_Def) /= N_Package_Declaration loop
Orig_Def := Parent (Orig_Def);
end loop;
end if;
if In_Same_Declarative_Part (Parent (N), Orig_Def) then
Same_Decl := True;
Set_Is_Pure (Def_Id); Set_Is_Pure (Def_Id);
if not Has_Pragma_Pure_Function (Def_Id) then if not Has_Pragma_Pure_Function (Def_Id) then
Set_Has_Pragma_Pure_Function (Def_Id); Set_Has_Pragma_Pure_Function (Def_Id);
Effective := True; Effective := True;
end if; end if;
end if;
exit when From_Aspect_Specification (N); exit when From_Aspect_Specification (N);
E := Homonym (E); E := Homonym (E);
...@@ -21094,6 +21112,10 @@ package body Sem_Prag is ...@@ -21094,6 +21112,10 @@ package body Sem_Prag is
Error_Msg_NE Error_Msg_NE
("pragma Pure_Function on& is redundant?r?", ("pragma Pure_Function on& is redundant?r?",
N, Entity (E_Id)); N, Entity (E_Id));
elsif not Same_Decl then
Error_Pragma_Arg
("pragma% argument must be in same declarative "
& "part", Arg1);
end if; end if;
end if; end if;
end Pure_Function; end Pure_Function;
...@@ -12024,6 +12024,50 @@ package body Sem_Util is ...@@ -12024,6 +12024,50 @@ package body Sem_Util is
and then Reverse_Storage_Order (Btyp); and then Reverse_Storage_Order (Btyp);
end In_Reverse_Storage_Order_Object; end In_Reverse_Storage_Order_Object;
------------------------------
-- In_Same_Declarative_Part --
------------------------------
function In_Same_Declarative_Part
(Context : Node_Id;
N : Node_Id) return Boolean
is
Cont : Node_Id := Context;
Nod : Node_Id;
begin
if Nkind (Cont) = N_Compilation_Unit_Aux then
Cont := Parent (Cont);
end if;
Nod := Parent (N);
while Present (Nod) loop
if Nod = Cont then
return True;
elsif Nkind_In (Nod, N_Accept_Statement,
N_Block_Statement,
N_Compilation_Unit,
N_Entry_Body,
N_Package_Body,
N_Package_Declaration,
N_Protected_Body,
N_Subprogram_Body,
N_Task_Body)
then
return False;
elsif Nkind (Nod) = N_Subunit then
Nod := Corresponding_Stub (Nod);
else
Nod := Parent (Nod);
end if;
end loop;
return False;
end In_Same_Declarative_Part;
-------------------------------------- --------------------------------------
-- In_Subprogram_Or_Concurrent_Unit -- -- In_Subprogram_Or_Concurrent_Unit --
-------------------------------------- --------------------------------------
......
...@@ -1399,6 +1399,12 @@ package Sem_Util is ...@@ -1399,6 +1399,12 @@ package Sem_Util is
-- Returns True if N denotes a component or subcomponent in a record or -- Returns True if N denotes a component or subcomponent in a record or
-- array that has Reverse_Storage_Order. -- array that has Reverse_Storage_Order.
function In_Same_Declarative_Part
(Context : Node_Id;
N : Node_Id) return Boolean;
-- True if the node N appears within the same declarative part denoted by
-- the node Context.
function In_Subprogram_Or_Concurrent_Unit return Boolean; function In_Subprogram_Or_Concurrent_Unit return Boolean;
-- Determines if the current scope is within a subprogram compilation unit -- Determines if the current scope is within a subprogram compilation unit
-- (inside a subprogram declaration, subprogram body, or generic subprogram -- (inside a subprogram declaration, subprogram body, or generic subprogram
......
2018-05-22 Justin Squirek <squirek@adacore.com>
* gnat.dg/pure_function1.adb, gnat.dg/pure_function1.ads,
gnat.dg/pure_function2.adb, gnat.dg/pure_function2.ads: New testcases.
2018-05-22 Richard Sandiford <richard.sandiford@linaro.org> 2018-05-22 Richard Sandiford <richard.sandiford@linaro.org>
PR middle-end/85862 PR middle-end/85862
......
-- { dg-do compile }
package body Pure_Function1 is
function F return Integer is (0);
pragma Pure_Function (F); -- { dg-error "pragma \"Pure_Function\" argument must be in same declarative part" }
pragma Pure_Function (F); -- { dg-error "pragma \"Pure_Function\" argument must be in same declarative part" }
pragma Pure_Function (F); -- { dg-error "pragma \"Pure_Function\" argument must be in same declarative part" }
end;
package Pure_Function1 is
function F return Integer;
pragma Pure_Function (F);
pragma Pure_Function (F);
pragma Pure_Function (F);
end;
-- { dg-do compile }
function Pure_Function2 (X : Integer) return Integer is
begin
return X;
end Pure_Function2;
pragma Pure_Function (Pure_Function2); -- { dg-error "pragma \"Pure_Function\" argument must be in same declarative part" }
pragma Pure_Function (Pure_Function2); -- { dg-error "pragma \"Pure_Function\" argument must be in same declarative part" }
pragma Pure_Function (Pure_Function2); -- { dg-error "pragma \"Pure_Function\" argument must be in same declarative part" }
function Pure_Function2 (X : Integer) return Integer with Pure_Function;
pragma Pure_Function (Pure_Function2);
pragma Pure_Function (Pure_Function2);
pragma Pure_Function (Pure_Function2);
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment