This patch implements the rules defined in SPARK 2014 RM section C.6. The rules forbit certain constructs to be labelled as volatile.
------------ -- Source -- ------------ -- shared_variables.ads package Shared_Variables with SPARK_Mode => On is type T is new Integer with Volatile; -- OK type Colour is (Red, Green, Blue) with Volatile; -- OK S : Integer with Volatile; -- OK type R is record F1 : Integer; F2 : Integer with Volatile; -- illegal, SPARK RM C.6(1) F3 : Boolean; end record; type R2 is record F1 : Integer; F2 : T; -- illegal, SPARK RM C.6(2) end record; type R3 (D : Colour) is record -- illegal, SPARK RM C.6(3) Intensity : Natural; end record; type R4 (D : Boolean) is record F1 : Integer; end record with Volatile; -- illegal, SPARK RM C.6(4) type R5 (D : Boolean := False) is record F1 : Integer; end record; -- legal SV : R5 with Volatile; -- illegal, SPARK RM C.6(4) type R6 is tagged record F1 : Integer; end record with Volatile; -- illegal, SPARK RM C.6(5) type R7 is tagged record F1 : Integer; end record; -- legal SV2 : R7 with Volatile; -- illegal, SPARK RM C.6(5) end Shared_Variables; ---------------------------- -- Compilation and output -- ---------------------------- $ gcc -c shared_variables.ads shared_variables.ads:15:07: component "F2" of non-volatile record type "R" cannot be volatile shared_variables.ads:15:25: argument of aspect "Volatile" must denote a full type or object declaration shared_variables.ads:21:07: component "F2" of non-volatile record type "R2" cannot be volatile shared_variables.ads:24:13: discriminant cannot be volatile shared_variables.ads:28:09: discriminated type "R4" cannot be volatile shared_variables.ads:36:04: discriminated object "SV" cannot be volatile shared_variables.ads:38:09: tagged type "R6" cannot be volatile shared_variables.ads:46:04: tagged object "SV2" cannot be volatile Tested on x86_64-pc-linux-gnu, committed on trunk 2014-05-21 Hristian Kirtchev <kirtc...@adacore.com> * freeze.adb (Freeze_Record_Type): Ensure that a discriminated or a tagged type is not labelled as volatile. Ensure that a non-volatile type has no volatile components. * sem_ch3.adb (Analyze_Object_Contract): Add local constant Obj_Typ. Code reformatting. Ensure that a discriminated or tagged object is not labelled as volatile. * sem_prag.adb (Process_Atomic_Shared_Volatile): Ensure that pragma Volatile applies to a full type declaration or an object declaration when SPARK mode is on.
Index: sem_ch3.adb =================================================================== --- sem_ch3.adb (revision 210695) +++ sem_ch3.adb (working copy) @@ -2980,12 +2980,13 @@ ----------------------------- procedure Analyze_Object_Contract (Obj_Id : Entity_Id) is - AR_Val : Boolean := False; - AW_Val : Boolean := False; - ER_Val : Boolean := False; - EW_Val : Boolean := False; - Prag : Node_Id; - Seen : Boolean := False; + Obj_Typ : constant Entity_Id := Etype (Obj_Id); + AR_Val : Boolean := False; + AW_Val : Boolean := False; + ER_Val : Boolean := False; + EW_Val : Boolean := False; + Prag : Node_Id; + Seen : Boolean := False; begin if Ekind (Obj_Id) = E_Constant then @@ -3008,26 +3009,43 @@ -- they are not standard Ada legality rules. if SPARK_Mode = On then + if Is_SPARK_Volatile_Object (Obj_Id) then - -- A non-volatile object cannot have volatile components - -- (SPARK RM 7.1.3(7)). + -- The declaration of a volatile object must appear at the + -- library level (SPARK RM 7.1.3(7), C.6(6)). - if not Is_SPARK_Volatile_Object (Obj_Id) - and then Has_Volatile_Component (Etype (Obj_Id)) - then - Error_Msg_N - ("non-volatile variable & cannot have volatile components", - Obj_Id); + if not Is_Library_Level_Entity (Obj_Id) then + Error_Msg_N + ("volatile variable & must be declared at library level", + Obj_Id); - -- The declaration of a volatile object must appear at the library - -- level. + -- An object of a discriminated type cannot be volatile + -- (SPARK RM C.6(4)). - elsif Is_SPARK_Volatile_Object (Obj_Id) - and then not Is_Library_Level_Entity (Obj_Id) - then - Error_Msg_N - ("volatile variable & must be declared at library level " - & "(SPARK RM 7.1.3(5))", Obj_Id); + elsif Has_Discriminants (Obj_Typ) then + Error_Msg_N + ("discriminated object & cannot be volatile", Obj_Id); + + -- An object of a tagged type cannot be volatile + -- (SPARK RM C.6(5)). + + elsif Is_Tagged_Type (Obj_Typ) then + Error_Msg_N ("tagged object & cannot be volatile", Obj_Id); + end if; + + -- The object is not volatile + + else + -- A non-volatile object cannot have volatile components + -- (SPARK RM 7.1.3(7)). + + if not Is_SPARK_Volatile_Object (Obj_Id) + and then Has_Volatile_Component (Obj_Typ) + then + Error_Msg_N + ("non-volatile object & cannot have volatile components", + Obj_Id); + end if; end if; end if; Index: sem_prag.adb =================================================================== --- sem_prag.adb (revision 210690) +++ sem_prag.adb (working copy) @@ -6387,6 +6387,21 @@ Error_Pragma_Arg ("inappropriate entity for pragma%", Arg1); end if; + + -- The following check are only relevant when SPARK_Mode is on as + -- those are not a standard Ada legality rule. Pragma Volatile can + -- only apply to a full type declaration or an object declaration + -- (SPARK RM C.6(1)). + + if SPARK_Mode = On + and then Prag_Id = Pragma_Volatile + and then not Nkind_In (K, N_Full_Type_Declaration, + N_Object_Declaration) + then + Error_Pragma_Arg + ("argument of pragma % must denote a full type or object " + & "declaration", Arg1); + end if; end Process_Atomic_Shared_Volatile; ------------------------------------------- Index: freeze.adb =================================================================== --- freeze.adb (revision 210695) +++ freeze.adb (working copy) @@ -3314,6 +3314,45 @@ end if; end if; + -- The following checks are only relevant when SPARK_Mode is on as + -- they are not standard Ada legality rules. + + if SPARK_Mode = On then + if Is_SPARK_Volatile_Object (Rec) then + + -- A discriminated type cannot be volatile (SPARK RM C.6(4)) + + if Has_Discriminants (Rec) then + Error_Msg_N ("discriminated type & cannot be volatile", Rec); + + -- A tagged type cannot be volatile (SPARK RM C.6(5)) + + elsif Is_Tagged_Type (Rec) then + Error_Msg_N ("tagged type & cannot be volatile", Rec); + end if; + + -- A non-volatile record type cannot contain volatile components + -- (SPARK RM C.6(2)). The check is performed at freeze point + -- because the volatility status of the record type and its + -- components is clearly known. + + else + Comp := First_Component (Rec); + while Present (Comp) loop + if Comes_From_Source (Comp) + and then Is_SPARK_Volatile_Object (Comp) + then + Error_Msg_Name_1 := Chars (Rec); + Error_Msg_N + ("component & of non-volatile record type % cannot be " + & "volatile", Comp); + end if; + + Next_Component (Comp); + end loop; + end if; + end if; + -- All done if not a full record definition if Ekind (Rec) /= E_Record_Type then