This change improves the SCO generation circuitry for pragma Debug. Specific support is added for dyadic pragma Debug (where the first argument is now treated as a P decision). SCO generation is suppressed altogether for any pragma Debug, or decision nested therein, if the pragma is not enabled.
The below unit must produce the indicated SCOs: $ gcc -c -gnateS pragma_debug_scos.adb CS 8:4-8:4 $ gcc -c -gnata -gnateS pragma_debug_scos.adb CS P4:4-4:28 P5:4-5:65 P6:4-6:31 P7:4-7:74 8:4-8:4 CX &5:56 c5:54-5:54 c5:65-5:65 CP 6:4 c6:18-6:18 CP 7:4 c7:18-7:18 CX |7:66 c7:64-7:64 c7:74-7:74 with Ada.Text_IO; use Ada.Text_IO; procedure Pragma_Debug_SCOs (A, B : Boolean) is begin pragma Debug (Put_Line ("foo")); pragma Debug (Put_Line ("A&&B: " & Boolean'Image (A and then B))); pragma Debug (A, Put_Line ("A is True")); pragma Debug (B, Put_Line ("B True, A||B:" & Boolean'Image (A or else B))); null; end Pragma_Debug_SCOs; Tested on x86_64-pc-linux-gnu, committed on trunk 2011-08-05 Thomas Quinot <qui...@adacore.com> * scos.ads: Update documentation of SCO table. Pragma statements can now be marked as disabled (using 'p' instead of 'P' as the statement kind). * par_sco.ads, par_sco.adb: Implement the above change. (Process_Decisions_Defer): Generate a P decision for the first parameter of a dyadic pragma Debug. * sem_prag.adb (Analyze_Pragma, case Debug): Mark pragma as enabled if necessary. * put_scos.adb: Code simplification based on above change.
Index: par_sco.adb =================================================================== --- par_sco.adb (revision 177431) +++ par_sco.adb (working copy) @@ -69,9 +69,9 @@ -- We need to be able to get to conditions quickly for handling the calls -- to Set_SCO_Condition efficiently, and similarly to get to pragmas to - -- handle calls to Set_SCO_Pragma_Enabled. For this purpose we identify the - -- conditions and pragmas in the table by their starting sloc, and use this - -- hash table to map from these starting sloc values to SCO_Table indexes. + -- handle calls to Set_SCO_Pragma_Enabled. For this purpose we identify + -- the conditions and pragmas in the table by their starting sloc, and use + -- this hash table to map from these sloc values to SCO_Table indexes. type Header_Num is new Integer range 0 .. 996; -- Type for hash table headers @@ -101,7 +101,10 @@ -- excluding OR and AND) and returns True if so, False otherwise, it does -- no other processing. - procedure Process_Decisions (N : Node_Id; T : Character); + procedure Process_Decisions + (N : Node_Id; + T : Character; + Pragma_Sloc : Source_Ptr); -- If N is Empty, has no effect. Otherwise scans the tree for the node N, -- to output any decisions it contains. T is one of IEGPWX (for context of -- expression: if/exit when/entry guard/pragma/while/expression). If T is @@ -109,7 +112,10 @@ -- decision is always present (at the very least a simple decision is -- present at the top level). - procedure Process_Decisions (L : List_Id; T : Character); + procedure Process_Decisions + (L : List_Id; + T : Character; + Pragma_Sloc : Source_Ptr); -- Calls above procedure for each element of the list L procedure Set_Table_Entry @@ -316,13 +322,17 @@ -- Version taking a list - procedure Process_Decisions (L : List_Id; T : Character) is + procedure Process_Decisions + (L : List_Id; + T : Character; + Pragma_Sloc : Source_Ptr) + is N : Node_Id; begin if L /= No_List then N := First (L); while Present (N) loop - Process_Decisions (N, T); + Process_Decisions (N, T, Pragma_Sloc); Next (N); end loop; end if; @@ -330,11 +340,14 @@ -- Version taking a node - Pragma_Sloc : Source_Ptr := No_Location; - -- While processing decisions within a pragma Assert/Debug/PPC, this is set - -- to the sloc of the pragma. + Current_Pragma_Sloc : Source_Ptr := No_Location; + -- While processing a pragma, this is set to the sloc of the N_Pragma node - procedure Process_Decisions (N : Node_Id; T : Character) is + procedure Process_Decisions + (N : Node_Id; + T : Character; + Pragma_Sloc : Source_Ptr) + is Mark : Nat; -- This is used to mark the location of a decision sequence in the SCO -- table. We use it for backing out a simple decision in an expression @@ -466,14 +479,6 @@ Loc := Sloc (Parent (Parent (N))); - if T = 'P' then - - -- Record sloc of pragma (pragmas don't nest) - - pragma Assert (Pragma_Sloc = No_Location); - Pragma_Sloc := Loc; - end if; - when 'X' => -- For an expression, no Sloc @@ -493,17 +498,6 @@ To => No_Location, Last => False, Pragma_Sloc => Pragma_Sloc); - - if T = 'P' then - - -- For pragmas we also must make an entry in the hash table for - -- later access by Set_SCO_Pragma_Enabled. We set the pragma as - -- disabled now, the call will change C2 to 'e' to enable the - -- pragma header entry. - - SCO_Table.Table (SCO_Table.Last).C2 := 'd'; - Condition_Pragma_Hash_Table.Set (Loc, SCO_Table.Last); - end if; end Output_Header; ------------------------------ @@ -521,7 +515,7 @@ Process_Decision_Operand (Right_Opnd (N)); else - Process_Decisions (N, 'X'); + Process_Decisions (N, 'X', Pragma_Sloc); end if; end Process_Decision_Operand; @@ -595,9 +589,9 @@ Thnx : constant Node_Id := Next (Cond); Elsx : constant Node_Id := Next (Thnx); begin - Process_Decisions (Cond, 'I'); - Process_Decisions (Thnx, 'X'); - Process_Decisions (Elsx, 'X'); + Process_Decisions (Cond, 'I', Pragma_Sloc); + Process_Decisions (Thnx, 'X', Pragma_Sloc); + Process_Decisions (Elsx, 'X', Pragma_Sloc); return Skip; end; @@ -635,12 +629,6 @@ end if; Traverse (N); - - -- Reset Pragma_Sloc after full subtree traversal - - if T = 'P' then - Pragma_Sloc := No_Location; - end if; end Process_Decisions; ----------- @@ -771,8 +759,12 @@ -- disabled. if Index /= 0 then - pragma Assert (SCO_Table.Table (Index).C1 = 'P'); - return SCO_Table.Table (Index).C2 = 'd'; + declare + T : SCO_Table_Entry renames SCO_Table.Table (Index); + begin + pragma Assert (T.C1 = 'S' or else T.C1 = 's'); + return T.C2 = 'p'; + end; else return False; @@ -899,8 +891,17 @@ -- The test here for zero is to deal with possible previous errors if Index /= 0 then - pragma Assert (SCO_Table.Table (Index).C1 = 'P'); - SCO_Table.Table (Index).C2 := 'e'; + declare + T : SCO_Table_Entry renames SCO_Table.Table (Index); + begin + -- Called multiple times for the same sloc (need to allow for + -- C2 = 'P') ??? + + pragma Assert ((T.C1 = 'S' or else T.C1 = 's') + and then + (T.C2 = 'p' or else T.C2 = 'P')); + T.C2 := 'P'; + end; end if; end Set_SCO_Pragma_Enabled; @@ -987,12 +988,14 @@ Nod : Node_Id; Lst : List_Id; Typ : Character; + Plo : Source_Ptr; end record; -- Used to store a single entry in the following table. Nod is the node to -- be searched for decisions for the case of Process_Decisions_Defer with a -- node argument (with Lst set to No_List. Lst is the list to be searched -- for decisions for the case of Process_Decisions_Defer with a List - -- argument (in which case Nod is set to Empty). + -- argument (in which case Nod is set to Empty). Plo is the sloc of the + -- enclosing pragma, if any. package SD is new Table.Table ( Table_Component_Type => SD_Entry, @@ -1077,11 +1080,15 @@ SCE : SC_Entry renames SC.Table (J); Pragma_Sloc : Source_Ptr := No_Location; begin - -- For the statement SCO for a pragma, set Pragma_Sloc so that - -- the SCO can be omitted if the pragma is disabled. + -- For the statement SCO for a pragma controlled by + -- Set_SCO_Pragma_Enable, set Pragma_Sloc so that the SCO (and + -- those of any nested decision) is emitted only if the pragma + -- is enabled. - if SCE.Typ = 'P' then + if SCE.Typ = 'p' then Pragma_Sloc := SCE.From; + Condition_Pragma_Hash_Table.Set + (Pragma_Sloc, SCO_Table.Last + 1); end if; Set_Table_Entry @@ -1105,9 +1112,9 @@ SDE : SD_Entry renames SD.Table (J); begin if Present (SDE.Nod) then - Process_Decisions (SDE.Nod, SDE.Typ); + Process_Decisions (SDE.Nod, SDE.Typ, SDE.Plo); else - Process_Decisions (SDE.Lst, SDE.Typ); + Process_Decisions (SDE.Lst, SDE.Typ, SDE.Plo); end if; end; end loop; @@ -1148,12 +1155,12 @@ procedure Process_Decisions_Defer (N : Node_Id; T : Character) is begin - SD.Append ((N, No_List, T)); + SD.Append ((N, No_List, T, Current_Pragma_Sloc)); end Process_Decisions_Defer; procedure Process_Decisions_Defer (L : List_Id; T : Character) is begin - SD.Append ((Empty, L, T)); + SD.Append ((Empty, L, T, Current_Pragma_Sloc)); end Process_Decisions_Defer; -- Start of processing for Traverse_Declarations_Or_Statements @@ -1391,43 +1398,71 @@ -- Pragma when N_Pragma => - Extend_Statement_Sequence (N, 'P'); + -- Record sloc of pragma (pragmas don't nest) + + pragma Assert (Current_Pragma_Sloc = No_Location); + Current_Pragma_Sloc := Sloc (N); + -- Processing depends on the kind of pragma - case Pragma_Name (N) is - when Name_Assert | - Name_Check | - Name_Precondition | - Name_Postcondition => + declare + Nam : constant Name_Id := Pragma_Name (N); + Arg : Node_Id := First (Pragma_Argument_Associations (N)); + Typ : Character; - -- For Assert/Check/Precondition/Postcondition, we - -- must generate a P entry for the decision. Note that - -- this is done unconditionally at this stage. Output - -- for disabled pragmas is suppressed later on, when - -- we output the decision line in Put_SCOs. + begin + case Nam is + when Name_Assert | + Name_Check | + Name_Precondition | + Name_Postcondition => - declare - Nam : constant Name_Id := - Chars (Pragma_Identifier (N)); - Arg : Node_Id := - First (Pragma_Argument_Associations (N)); + -- For Assert/Check/Precondition/Postcondition, we + -- must generate a P entry for the decision. Note + -- that this is done unconditionally at this stage. + -- Output for disabled pragmas is suppressed later + -- on, when we output the decision line in + -- Put_SCOs, depending on marker sets by + -- Set_SCO_Pragma_Disabled. - begin if Nam = Name_Check then Next (Arg); end if; Process_Decisions_Defer (Expression (Arg), 'P'); - end; + Typ := 'p'; - -- For all other pragmas, we generate decision entries - -- for any embedded expressions. + when Name_Debug => + if Present (Arg) and then Present (Next (Arg)) then - when others => - Process_Decisions_Defer (N, 'X'); - end case; + -- Case of a dyadic pragma Debug: first argument + -- is a P decision, any nested decision in the + -- second argument is an X decision. + Process_Decisions_Defer (Expression (Arg), 'P'); + Next (Arg); + end if; + + Process_Decisions_Defer (Expression (Arg), 'X'); + Typ := 'p'; + + -- For all other pragmas, we generate decision entries + -- for any embedded expressions, and the pragma is + -- never disabled. + + when others => + Process_Decisions_Defer (N, 'X'); + Typ := 'P'; + end case; + + -- Add statement SCO + + Extend_Statement_Sequence (N, Typ); + + Current_Pragma_Sloc := No_Location; + end; + -- Object declaration. Ignored if Prev_Ids is set, since the -- parser generates multiple instances of the whole declaration -- if there is more than one identifier declared, and we only @@ -1512,7 +1547,7 @@ -- Now output any embedded decisions - Process_Decisions (N, 'X'); + Process_Decisions (N, 'X', No_Location); end Traverse_Generic_Instantiation; ------------------------------------------ @@ -1521,7 +1556,7 @@ procedure Traverse_Generic_Package_Declaration (N : Node_Id) is begin - Process_Decisions (Generic_Formal_Declarations (N), 'X'); + Process_Decisions (Generic_Formal_Declarations (N), 'X', No_Location); Traverse_Package_Declaration (N); end Traverse_Generic_Package_Declaration; Index: par_sco.ads =================================================================== --- par_sco.ads (revision 177431) +++ par_sco.ads (working copy) @@ -50,9 +50,9 @@ -- original tree associated with Cond. procedure Set_SCO_Pragma_Enabled (Loc : Source_Ptr); - -- This procedure is called from Sem_Prag when a pragma is enabled (i.e. - -- when the Pragma_Enabled flag is set). Loc is the Sloc of the N_Pragma - -- node. This is used to enable the corresponding SCO table entry. Note + -- This procedure is called from Sem_Prag when a pragma is disabled (i.e. + -- when the Pragma_Enabled flag is unset). Loc is the Sloc of the N_Pragma + -- node. This is used to disable the corresponding SCO table entry. Note -- that we use the Sloc as the key here, since in the generic case, the -- analysis is on a copy of the node, which is different from the node -- seen by Par_SCO in the parse tree (but the Sloc values are the same). Index: scos.ads =================================================================== --- scos.ads (revision 177431) +++ scos.ads (working copy) @@ -152,6 +152,7 @@ -- E EXIT statement -- F FOR loop statement (from FOR through end of iteration scheme) -- I IF statement (from IF through end of condition) + -- p disabled PRAGMA -- P PRAGMA -- R extended RETURN statement -- W WHILE loop statement (from WHILE through end of condition) @@ -194,12 +195,12 @@ -- Decisions are either simple or complex. A simple decision is a top -- level boolean expression that has only one condition and that occurs -- in the context of a control structure in the source program, including - -- WHILE, IF, EXIT WHEN, or in an Assert, Check, Pre_Condition or - -- Post_Condition pragma. For pragmas, decision SCOs are generated only - -- if the corresponding pragma is enabled. Note that a top level boolean - -- expression with only one condition that occurs in any other context, - -- for example as right hand side of an assignment, is not considered to - -- be a (simple) decision. + -- WHILE, IF, EXIT WHEN, or immediately within an Assert, Check, + -- Pre_Condition or Post_Condition pragma, or as the first argument of a + -- dyadic pragma Debug. Note that a top level boolean expression with + -- only one condition that occurs in any other context, for example as + -- right hand side of an assignment, is not considered to be a (simple) + -- decision. -- A complex decision is a top level boolean expression that has more -- than one condition. A complex decision may occur in any boolean @@ -336,6 +337,10 @@ -- entries appear in one logical statement sequence, continuation lines -- are marked by Cc and appear immediately after the CC line. + -- Disabled pragmas + + -- No SCO is generated for disabled pragmas. + --------------------------------------------------------------------- -- Internal table used to store Source Coverage Obligations (SCOs) -- --------------------------------------------------------------------- @@ -392,7 +397,7 @@ -- Decision (PRAGMA) -- C1 = 'P' - -- C2 = 'e'/'d' for enabled/disabled + -- C2 = ' ' -- From = PRAGMA token -- To = No_Source_Location -- Last = unused @@ -400,14 +405,11 @@ -- Note: when the parse tree is first scanned, we unconditionally build -- a pragma decision entry for any decision in a pragma (here as always -- in SCO contexts, the only pragmas with decisions are Assert, Check, - -- Precondition and Postcondition), and we mark the pragma as disabled. + -- dyadic Debug, Precondition and Postcondition). -- - -- During analysis, if the pragma is enabled, Set_SCO_Pragma_Enabled to - -- mark the SCO decision table entry as enabled (C2 set to 'e'). Then - -- in Put_SCOs, we only output the decision for a pragma if C2 is 'e'. - -- - -- When we read SCOs from an ALI file (in Get_SCOs), we always set C2 - -- to 'e', since clearly the pragma is enabled if it was written out. + -- During analysis, if the pragma is enabled, Set_SCO_Pragma_Enabled + -- marks the statement SCO table entry as enaabled (C1 changed from 'p' + -- to 'P') to cause the entry to be emitted in Put_SCOs. -- Decision (Expression) -- C1 = 'X' Index: sem_prag.adb =================================================================== --- sem_prag.adb (revision 177434) +++ sem_prag.adb (working copy) @@ -1794,7 +1794,7 @@ (Get_Pragma_Arg (Arg2), Standard_String); end if; - -- Record if pragma is enabled + -- Record if pragma is disabled if Check_Enabled (Pname) then Set_SCO_Pragma_Enabled (Loc); @@ -7604,6 +7604,10 @@ (Boolean_Literals (Debug_Pragmas_Enabled and Expander_Active), Loc); + if Debug_Pragmas_Enabled then + Set_SCO_Pragma_Enabled (Loc); + end if; + if Arg_Count = 2 then Cond := Make_And_Then (Loc, Index: put_scos.adb =================================================================== --- put_scos.adb (revision 177431) +++ put_scos.adb (working copy) @@ -107,9 +107,8 @@ Ctr := 0; Continuation := False; loop - if SCO_Table.Table (Start).C2 = 'P' - and then SCO_Pragma_Disabled - (SCO_Table.Table (Start).Pragma_Sloc) + if SCO_Pragma_Disabled + (SCO_Table.Table (Start).Pragma_Sloc) then goto Next_Statement; end if; @@ -160,13 +159,10 @@ when 'I' | 'E' | 'G' | 'P' | 'W' | 'X' => Start := Start + 1; - -- For disabled pragma, or nested decision nested, skip + -- For disabled pragma, or nested decision therein, skip -- decision output. - if (T.C1 = 'P' and then T.C2 = 'd') - or else - SCO_Pragma_Disabled (T.Pragma_Sloc) - then + if SCO_Pragma_Disabled (T.Pragma_Sloc) then while not SCO_Table.Table (Start).Last loop Start := Start + 1; end loop; Index: get_scos.adb =================================================================== --- get_scos.adb (revision 177431) +++ get_scos.adb (working copy) @@ -315,7 +315,6 @@ declare Loc : Source_Location; - C2v : Character; begin -- Acquire location information @@ -326,18 +325,9 @@ Get_Source_Location (Loc); end if; - -- C2 is a space except for pragmas where it is 'e' since - -- clearly the pragma is enabled if it was written out. - - if C = 'P' then - C2v := 'e'; - else - C2v := ' '; - end if; - Add_SCO (C1 => Dtyp, - C2 => C2v, + C2 => ' ', From => Loc, To => No_Source_Location, Last => False);