This change removes an annoying irregularity in N_Pragma nodes, which had the last argument copied in two distinct syntactic descendents (Pragma_Argument_Associations and Debug_Statement) for a pragma Debug. This caused duplicated SCO information to be emitted for decisions occurring in the actual parameters of the procedure call enclosed in such a pragma.
The Debug_Statement attribute is actually superfluous, and now removed. The SCO information in the ALI file for the following compilation must contain exactly one CX line: $ gcc -c -gnateS dup_sco.adb $ grep "^CX" dup_sco.ali CX &7:28 c7:26-7:26 c7:37-7:37 pragma Debug_Policy (Check); procedure Dup_SCO (A, B : Boolean) is procedure Assert (X : Boolean) is begin null; end Assert; pragma Debug (Assert (A and then B)); begin null; end Dup_SCO; Tested on x86_64-pc-linux-gnu, committed on trunk 2011-08-04 Thomas Quinot <qui...@adacore.com> * sinfo.ads, sinfo.adb (Debug_Statement, Set_Debug_Statement): Remove. * tbuild.ads, tbuild.adb (Make_Pragma): Adjust accordingly. * sinfo-cn.ads, sinfo-cn.adb (Change_Name_To_Procedure_Call_Statement): New subprogram, moved here from... * par.adb, par-ch5.adb (P_Statement_Name): ... here. * par-prag.adb (Par.Prag, case Pragma_Debug): Do not perform any rewriting of the last argument into a procedure call statement here... * sem_prag.adb (Analyze_Pragma, case Pragma_Debug): ...do it there instead.
Index: sinfo.adb =================================================================== --- sinfo.adb (revision 177275) +++ sinfo.adb (working copy) @@ -661,14 +661,6 @@ return Node5 (N); end Dcheck_Function; - function Debug_Statement - (N : Node_Id) return Node_Id is - begin - pragma Assert (False - or else NT (N).Nkind = N_Pragma); - return Node3 (N); - end Debug_Statement; - function Declarations (N : Node_Id) return List_Id is begin @@ -3712,14 +3704,6 @@ Set_Node5 (N, Val); -- semantic field, no parent set end Set_Dcheck_Function; - procedure Set_Debug_Statement - (N : Node_Id; Val : Node_Id) is - begin - pragma Assert (False - or else NT (N).Nkind = N_Pragma); - Set_Node3_With_Parent (N, Val); - end Set_Debug_Statement; - procedure Set_Declarations (N : Node_Id; Val : List_Id) is begin Index: sinfo.ads =================================================================== --- sinfo.ads (revision 177275) +++ sinfo.ads (working copy) @@ -764,15 +764,6 @@ -- This field is present in an N_Variant node, It references the entity -- for the discriminant checking function for the variant. - -- Debug_Statement (Node3) - -- This field is present in an N_Pragma node. It is used only for a Debug - -- pragma. The parameter is of the form of an expression, as required by - -- the pragma syntax, but is actually a procedure call. To simplify - -- semantic processing, the parser creates a copy of the argument - -- rearranged into a procedure call statement and places it in the - -- Debug_Statement field. Note that this field is considered syntactic - -- field, since it is created by the parser. - -- Default_Expression (Node5-Sem) -- This field is Empty if there is no default expression. If there is a -- simple default expression (one with no side effects), then this field @@ -2069,7 +2060,6 @@ -- Sloc points to PRAGMA -- Next_Pragma (Node1-Sem) -- Pragma_Argument_Associations (List2) (set to No_List if none) - -- Debug_Statement (Node3) (set to Empty if not Debug) -- Pragma_Identifier (Node4) -- Next_Rep_Item (Node5-Sem) -- Pragma_Enabled (Flag5-Sem) @@ -8201,9 +8191,6 @@ function Dcheck_Function (N : Node_Id) return Entity_Id; -- Node5 - function Debug_Statement - (N : Node_Id) return Node_Id; -- Node3 - function Declarations (N : Node_Id) return List_Id; -- List2 @@ -9173,9 +9160,6 @@ procedure Set_Dcheck_Function (N : Node_Id; Val : Entity_Id); -- Node5 - procedure Set_Debug_Statement - (N : Node_Id; Val : Node_Id); -- Node3 - procedure Set_Declarations (N : Node_Id; Val : List_Id); -- List2 @@ -10105,7 +10089,7 @@ N_Pragma => (1 => False, -- Next_Pragma (Node1-Sem) 2 => True, -- Pragma_Argument_Associations (List2) - 3 => True, -- Debug_Statement (Node3) + 3 => False, -- unused 4 => True, -- Pragma_Identifier (Node4) 5 => False), -- Next_Rep_Item (Node5-Sem) @@ -11732,7 +11716,6 @@ pragma Inline (Corresponding_Spec); pragma Inline (Corresponding_Stub); pragma Inline (Dcheck_Function); - pragma Inline (Debug_Statement); pragma Inline (Declarations); pragma Inline (Default_Expression); pragma Inline (Default_Storage_Pool); @@ -12053,7 +12036,6 @@ pragma Inline (Set_Corresponding_Spec); pragma Inline (Set_Corresponding_Stub); pragma Inline (Set_Dcheck_Function); - pragma Inline (Set_Debug_Statement); pragma Inline (Set_Declarations); pragma Inline (Set_Default_Expression); pragma Inline (Set_Default_Storage_Pool); Index: sem_prag.adb =================================================================== --- sem_prag.adb (revision 177335) +++ sem_prag.adb (working copy) @@ -7430,7 +7430,8 @@ -- pragma Debug ([boolean_EXPRESSION,] PROCEDURE_CALL_STATEMENT); when Pragma_Debug => Debug : declare - Cond : Node_Id; + Cond : Node_Id; + Call : Node_Id; begin GNAT_Pragma; @@ -7443,10 +7444,41 @@ if Arg_Count = 2 then Cond := Make_And_Then (Loc, - Left_Opnd => Relocate_Node (Cond), - Right_Opnd => Get_Pragma_Arg (Arg1)); + Left_Opnd => Relocate_Node (Cond), + Right_Opnd => Get_Pragma_Arg (Arg1)); + Call := Get_Pragma_Arg (Arg2); + else + Call := Get_Pragma_Arg (Arg1); end if; + if Nkind_In (Call, + N_Indexed_Component, + N_Function_Call, + N_Identifier, + N_Selected_Component) + then + -- If this pragma Debug comes from source, its argument was + -- parsed as a name form (which is syntactically identical). + -- Change it to a procedure call statement now. + + Change_Name_To_Procedure_Call_Statement (Call); + + elsif Nkind (Call) = N_Procedure_Call_Statement then + + -- Already in the form of a procedure call statement: nothing + -- to do (could happen in case of an internally generated + -- pragma Debug). + + null; + + else + -- All other cases: diagnose error + + Error_Msg + ("argument of pragma% is not procedure call", Sloc (Call)); + return; + end if; + -- Rewrite into a conditional with an appropriate condition. We -- wrap the procedure call in a block so that overhead from e.g. -- use of the secondary stack does not generate execution overhead @@ -7458,8 +7490,7 @@ Make_Block_Statement (Loc, Handled_Statement_Sequence => Make_Handled_Sequence_Of_Statements (Loc, - Statements => New_List ( - Relocate_Node (Debug_Statement (N)))))))); + Statements => New_List (Relocate_Node (Call))))))); Analyze (N); end Debug; Index: tbuild.adb =================================================================== --- tbuild.adb (revision 177275) +++ tbuild.adb (working copy) @@ -388,14 +388,12 @@ function Make_Pragma (Sloc : Source_Ptr; Chars : Name_Id; - Pragma_Argument_Associations : List_Id := No_List; - Debug_Statement : Node_Id := Empty) return Node_Id + Pragma_Argument_Associations : List_Id := No_List) return Node_Id is begin return Make_Pragma (Sloc, Pragma_Argument_Associations => Pragma_Argument_Associations, - Debug_Statement => Debug_Statement, Pragma_Identifier => Make_Identifier (Sloc, Chars)); end Make_Pragma; Index: tbuild.ads =================================================================== --- tbuild.ads (revision 177274) +++ tbuild.ads (working copy) @@ -6,7 +6,7 @@ -- -- -- S p e c -- -- -- --- Copyright (C) 1992-2010, Free Software Foundation, Inc. -- +-- Copyright (C) 1992-2011, Free Software Foundation, Inc. -- -- -- -- GNAT is free software; you can redistribute it and/or modify it under -- -- terms of the GNU General Public License as published by the Free Soft- -- @@ -150,8 +150,7 @@ function Make_Pragma (Sloc : Source_Ptr; Chars : Name_Id; - Pragma_Argument_Associations : List_Id := No_List; - Debug_Statement : Node_Id := Empty) return Node_Id; + Pragma_Argument_Associations : List_Id := No_List) return Node_Id; -- A convenient form of Make_Pragma not requiring a Pragma_Identifier -- argument (this argument is built from the value given for Chars). Index: par.adb =================================================================== --- par.adb (revision 177274) +++ par.adb (working copy) @@ -6,7 +6,7 @@ -- -- -- B o d y -- -- -- --- Copyright (C) 1992-2010, Free Software Foundation, Inc. -- +-- Copyright (C) 1992-2011, Free Software Foundation, Inc. -- -- -- -- GNAT is free software; you can redistribute it and/or modify it under -- -- terms of the GNU General Public License as published by the Free Soft- -- @@ -723,10 +723,6 @@ function P_Loop_Parameter_Specification return Node_Id; -- Used in loop constructs and quantified expressions. - function P_Statement_Name (Name_Node : Node_Id) return Node_Id; - -- Given a node representing a name (which is a call), converts it - -- to the syntactically corresponding procedure call statement. - function P_Sequence_Of_Statements (SS_Flags : SS_Rec) return List_Id; -- The argument indicates the acceptable termination tokens. -- See body in Par.Ch5 for details of the use of this parameter. Index: sinfo-cn.adb =================================================================== --- sinfo-cn.adb (revision 177274) +++ sinfo-cn.adb (working copy) @@ -6,7 +6,7 @@ -- -- -- B o d y -- -- -- --- Copyright (C) 1992-2008, Free Software Foundation, Inc. -- +-- Copyright (C) 1992-2011, Free Software Foundation, Inc. -- -- -- -- GNAT is free software; you can redistribute it and/or modify it under -- -- terms of the GNU General Public License as published by the Free Soft- -- @@ -30,7 +30,8 @@ -- general manner, but in some specific cases, the fields of related nodes -- have been deliberately layed out in a manner that permits such alteration. -with Atree; use Atree; +with Atree; use Atree; +with Snames; use Snames; package body Sinfo.CN is @@ -74,6 +75,58 @@ N := Extend_Node (N); end Change_Identifier_To_Defining_Identifier; + --------------------------------------------- + -- Change_Name_To_Procedure_Call_Statement -- + --------------------------------------------- + + procedure Change_Name_To_Procedure_Call_Statement (N : Node_Id) is + begin + -- Case of Indexed component, which is a procedure call with arguments + + if Nkind (N) = N_Indexed_Component then + declare + Prefix_Node : constant Node_Id := Prefix (N); + Exprs_Node : constant List_Id := Expressions (N); + + begin + Change_Node (N, N_Procedure_Call_Statement); + Set_Name (N, Prefix_Node); + Set_Parameter_Associations (N, Exprs_Node); + end; + + -- Case of function call node, which is a really a procedure call + + elsif Nkind (N) = N_Function_Call then + declare + Fname_Node : constant Node_Id := Name (N); + Params_List : constant List_Id := Parameter_Associations (N); + + begin + Change_Node (N, N_Procedure_Call_Statement); + Set_Name (N, Fname_Node); + Set_Parameter_Associations (N, Params_List); + end; + + -- Case of call to attribute that denotes a procedure. Here we just + -- leave the attribute reference unchanged. + + elsif Nkind (N) = N_Attribute_Reference + and then Is_Procedure_Attribute_Name (Attribute_Name (N)) + then + null; + + -- All other cases of names are parameterless procedure calls + + else + declare + Name_Node : constant Node_Id := Relocate_Node (N); + begin + Change_Node (N, N_Procedure_Call_Statement); + Set_Name (N, Name_Node); + end; + end if; + end Change_Name_To_Procedure_Call_Statement; + -------------------------------------------------------- -- Change_Operator_Symbol_To_Defining_Operator_Symbol -- -------------------------------------------------------- Index: sinfo-cn.ads =================================================================== --- sinfo-cn.ads (revision 177274) +++ sinfo-cn.ads (working copy) @@ -6,7 +6,7 @@ -- -- -- S p e c -- -- -- --- Copyright (C) 1992-2007, Free Software Foundation, Inc. -- +-- Copyright (C) 1992-2011, Free Software Foundation, Inc. -- -- -- -- GNAT is free software; you can redistribute it and/or modify it under -- -- terms of the GNU General Public License as published by the Free Soft- -- @@ -65,4 +65,9 @@ -- on return the Chars field is set to a copy of the contents of the -- Chars field of the Selector_Name field. + procedure Change_Name_To_Procedure_Call_Statement (N : Node_Id); + -- Some statements (procedure call statements) are in the form of a name + -- and are parsed as such. This routine takes the scanned name as input + -- and returns the corresponding N_Procedure_Call_Statement. + end Sinfo.CN; Index: par-prag.adb =================================================================== --- par-prag.adb (revision 177274) +++ par-prag.adb (working copy) @@ -358,43 +358,17 @@ -- Debug -- ----------- - -- pragma Debug (PROCEDURE_CALL_STATEMENT); + -- pragma Debug ([boolean_EXPRESSION,] PROCEDURE_CALL_STATEMENT); - -- This has to be processed by the parser because of the very peculiar - -- form of the second parameter, which is syntactically from a formal - -- point of view a function call (since it must be an expression), but - -- semantically we treat it as a procedure call (which has exactly the - -- same syntactic form, so that's why we can get away with this!) + when Pragma_Debug => + Check_No_Identifier (Arg1); - when Pragma_Debug => Debug : declare - Expr : Node_Id; - - begin if Arg_Count = 2 then - Check_No_Identifier (Arg1); Check_No_Identifier (Arg2); - Expr := New_Copy (Expression (Arg2)); - else Check_Arg_Count (1); - Check_No_Identifier (Arg1); - Expr := New_Copy (Expression (Arg1)); end if; - if Nkind (Expr) /= N_Indexed_Component - and then Nkind (Expr) /= N_Function_Call - and then Nkind (Expr) /= N_Identifier - and then Nkind (Expr) /= N_Selected_Component - then - Error_Msg - ("argument of pragma% is not procedure call", Sloc (Expr)); - raise Error_Resync; - else - Set_Debug_Statement - (Pragma_Node, P_Statement_Name (Expr)); - end if; - end Debug; - ------------------------------- -- Extensions_Allowed (GNAT) -- ------------------------------- Index: par-ch5.adb =================================================================== --- par-ch5.adb (revision 177274) +++ par-ch5.adb (working copy) @@ -6,7 +6,7 @@ -- -- -- B o d y -- -- -- --- Copyright (C) 1992-2010, Free Software Foundation, Inc. -- +-- Copyright (C) 1992-2011, Free Software Foundation, Inc. -- -- -- -- GNAT is free software; you can redistribute it and/or modify it under -- -- terms of the GNU General Public License as published by the Free Soft- -- @@ -24,9 +24,11 @@ ------------------------------------------------------------------------------ pragma Style_Checks (All_Checks); --- Turn off subprogram body ordering check. Subprograms are in order --- by RM section rather than alphabetical +-- Turn off subprogram body ordering check. Subprograms are in order by RM +-- section rather than alphabetical. +with Sinfo.CN; use Sinfo.CN; + separate (Par) package body Ch5 is @@ -499,8 +501,8 @@ -- we want to speed up as much as possible. elsif Token = Tok_Semicolon then - Append_To (Statement_List, - P_Statement_Name (Id_Node)); + Change_Name_To_Procedure_Call_Statement (Id_Node); + Append_To (Statement_List, Id_Node); Scan; -- past semicolon Statement_Required := False; @@ -652,8 +654,8 @@ -- means that the item we just scanned was a call. elsif Token = Tok_Semicolon then - Append_To (Statement_List, - P_Statement_Name (Name_Node)); + Change_Name_To_Procedure_Call_Statement (Name_Node); + Append_To (Statement_List, Name_Node); Scan; -- past semicolon Statement_Required := False; @@ -727,8 +729,8 @@ -- call with no parameters. if Token_Is_At_Start_Of_Line then - Append_To (Statement_List, - P_Statement_Name (Id_Node)); + Change_Name_To_Procedure_Call_Statement (Id_Node); + Append_To (Statement_List, Id_Node); T_Semicolon; -- to give error message Statement_Required := False; @@ -769,8 +771,8 @@ Append_To (Statement_List, P_Assignment_Statement (Name_Node)); else - Append_To (Statement_List, - P_Statement_Name (Name_Node)); + Change_Name_To_Procedure_Call_Statement (Name_Node); + Append_To (Statement_List, Name_Node); end if; TF_Semicolon; @@ -954,68 +956,6 @@ -- 5.1 Statement -- -------------------- - -- Parsed by P_Sequence_Of_Statements (5.1), except for the case - -- of a statement of the form of a name, which is handled here. The - -- argument passed in is the tree for the name which has been scanned - -- The returned value is the corresponding statement form. - - -- This routine is also used by Par.Prag for processing the procedure - -- call that appears as the second argument of a pragma Assert. - - -- Error recovery: cannot raise Error_Resync - - function P_Statement_Name (Name_Node : Node_Id) return Node_Id is - Stmt_Node : Node_Id; - - begin - -- Case of Indexed component, which is a procedure call with arguments - - if Nkind (Name_Node) = N_Indexed_Component then - declare - Prefix_Node : constant Node_Id := Prefix (Name_Node); - Exprs_Node : constant List_Id := Expressions (Name_Node); - - begin - Change_Node (Name_Node, N_Procedure_Call_Statement); - Set_Name (Name_Node, Prefix_Node); - Set_Parameter_Associations (Name_Node, Exprs_Node); - return Name_Node; - end; - - -- Case of function call node, which is a really a procedure call - - elsif Nkind (Name_Node) = N_Function_Call then - declare - Fname_Node : constant Node_Id := Name (Name_Node); - Params_List : constant List_Id := - Parameter_Associations (Name_Node); - - begin - Change_Node (Name_Node, N_Procedure_Call_Statement); - Set_Name (Name_Node, Fname_Node); - Set_Parameter_Associations (Name_Node, Params_List); - return Name_Node; - end; - - -- Case of call to attribute that denotes a procedure. Here we - -- just leave the attribute reference unchanged. - - elsif Nkind (Name_Node) = N_Attribute_Reference - and then Is_Procedure_Attribute_Name (Attribute_Name (Name_Node)) - then - return Name_Node; - - -- All other cases of names are parameterless procedure calls - - else - Stmt_Node := - New_Node (N_Procedure_Call_Statement, Sloc (Name_Node)); - Set_Name (Stmt_Node, Name_Node); - return Stmt_Node; - end if; - - end P_Statement_Name; - --------------------------- -- 5.1 Simple Statement -- ---------------------------