This patch simplifies the entity resolution machinery which detects an illegaly used SPARK volatile object with enabled external properties Async_Writers or Effective_Reads. The mechanism no longer traverses the parent chain as this is not needed.
------------ -- Source -- ------------ -- volatile_use.ads package Volatile_Use with SPARK_Mode => On is V1 : Integer with Volatile, Async_Writers => True; procedure Test_Eval_Order_OK (X : out Boolean) with Global => (Input => V1), Depends => (X => V1); procedure Test_Eval_Order_Bad1 (X : out Boolean) with Global => (Input => V1), Depends => (X => V1); procedure Test_Eval_Order_Bad2 (X : out Boolean) with Global => (Input => V1), Depends => (X => V1); end Volatile_Use; -- volatile_use.adb package body Volatile_Use with SPARK_Mode => On is procedure Test_Eval_Order_OK (X : out Boolean) is T1 : Integer; T2 : Integer; begin T1 := V1; T2 := V1; X := (T1 <= T2); end Test_Eval_Order_OK; procedure Test_Eval_Order_Bad1 (X : out Boolean) is T1 : Integer; begin T1 := V1; X := (T1 <= V1); end Test_Eval_Order_Bad1; procedure Test_Eval_Order_Bad2 (X : out Boolean) is begin X := (V1 <= V1); end Test_Eval_Order_Bad2; end Volatile_Use; ---------------------------- -- Compilation and output -- ---------------------------- $ gcc -c volatile_use.adb volatile_use.adb:15:19: volatile object cannot appear in this context (SPARK RM 7.1.3(13)) volatile_use.adb:20:13: volatile object cannot appear in this context (SPARK RM 7.1.3(13)) volatile_use.adb:20:19: volatile object cannot appear in this context (SPARK RM 7.1.3(13)) Tested on x86_64-pc-linux-gnu, committed on trunk 2014-02-25 Hristian Kirtchev <kirtc...@adacore.com> * sem_res.adb (Appears_In_Check): New routine. (Resolve_Entity_Name): Remove local variables Prev and Usage_OK. Par is now a constant. Remove the parent chain traversal as the placement of a volatile object with enabled property Async_Writers and/or Effective_Reads must appear immediately within a legal construct.
Index: sem_res.adb =================================================================== --- sem_res.adb (revision 208076) +++ sem_res.adb (working copy) @@ -6434,13 +6434,43 @@ -- Used to resolve identifiers and expanded names procedure Resolve_Entity_Name (N : Node_Id; Typ : Entity_Id) is - E : constant Entity_Id := Entity (N); - Par : Node_Id; - Prev : Node_Id; + function Appears_In_Check (Nod : Node_Id) return Boolean; + -- Denote whether an arbitrary node Nod appears in a check node - Usage_OK : Boolean := False; - -- Flag set when the use of a volatile object agrees with its context + ---------------------- + -- Appears_In_Check -- + ---------------------- + function Appears_In_Check (Nod : Node_Id) return Boolean is + Par : Node_Id; + + begin + -- Climb the parent chain looking for a check node + + Par := Nod; + while Present (Par) loop + if Nkind (Par) in N_Raise_xxx_Error then + return True; + + -- Prevent the search from going too far + + elsif Is_Body_Or_Package_Declaration (Par) then + exit; + end if; + + Par := Parent (Par); + end loop; + + return False; + end Appears_In_Check; + + -- Local variables + + E : constant Entity_Id := Entity (N); + Par : constant Node_Id := Parent (N); + + -- Start of processing for Resolve_Entity_Name + begin -- If garbage from errors, set to Any_Type and return @@ -6555,62 +6585,43 @@ (Async_Writers_Enabled (E) or else Effective_Reads_Enabled (E)) then - Par := Parent (N); - Prev := N; - while Present (Par) loop + -- The volatile object can appear on either side of an assignment - -- The volatile object can appear on either side of an assignment + if Nkind (Par) = N_Assignment_Statement then + null; - if Nkind (Par) = N_Assignment_Statement then - Usage_OK := True; - exit; + -- The volatile object is part of the initialization expression of + -- another object. Ensure that the climb of the parent chain came + -- from the expression side and not from the name side. - -- The volatile object is part of the initialization expression of - -- another object. Ensure that the climb of the parent chain came - -- from the expression side and not from the name side. + elsif Nkind (Par) = N_Object_Declaration + and then Present (Expression (Par)) + and then N = Expression (Par) + then + null; - elsif Nkind (Par) = N_Object_Declaration - and then Present (Expression (Par)) - and then Prev = Expression (Par) - then - Usage_OK := True; - exit; + -- The volatile object appears as an actual parameter in a call to an + -- instance of Unchecked_Conversion whose result is renamed. - -- The volatile object appears as an actual parameter in a call to - -- an instance of Unchecked_Conversion whose result is renamed. + elsif Nkind (Par) = N_Function_Call + and then Is_Unchecked_Conversion_Instance (Entity (Name (Par))) + and then Nkind (Parent (Par)) = N_Object_Renaming_Declaration + then + null; - elsif Nkind (Par) = N_Function_Call - and then Is_Unchecked_Conversion_Instance (Entity (Name (Par))) - and then Nkind (Parent (Par)) = N_Object_Renaming_Declaration - then - Usage_OK := True; - exit; + -- Assume that references to volatile objects that appear as actual + -- parameters in a procedure call are always legal. The full legality + -- check is done when the actuals are resolved. - -- Assume that references to volatile objects that appear as - -- actual parameters in a procedure call are always legal. The - -- full legality check is done when the actuals are resolved. + elsif Nkind (Par) = N_Procedure_Call_Statement then + null; - elsif Nkind (Par) = N_Procedure_Call_Statement then - Usage_OK := True; - exit; + -- Allow references to volatile objects in various checks - -- Allow references to volatile objects in various checks + elsif Appears_In_Check (Par) then + null; - elsif Nkind (Par) in N_Raise_xxx_Error then - Usage_OK := True; - exit; - - -- Prevent the search from going too far - - elsif Is_Body_Or_Package_Declaration (Par) then - exit; - end if; - - Prev := Par; - Par := Parent (Par); - end loop; - - if not Usage_OK then + else Error_Msg_N ("volatile object cannot appear in this context " & "(SPARK RM 7.1.3(13))", N);