Commit 10303118 by Bob Duff Committed by Arnaud Charlet

atree.ads, atree.adb (Traverse_Func): Walk Field2 last, and eliminate the…

atree.ads, atree.adb (Traverse_Func): Walk Field2 last, and eliminate the resulting tail recursion by hand.

2007-12-19  Bob Duff  <duff@adacore.com>

	* atree.ads, atree.adb (Traverse_Func): Walk Field2 last, and eliminate
	the resulting tail recursion by hand. This prevents running out of
	memory on deeply nested concatenations, since Field2 is where the left
	operand of concatenations is stored.
	Fix bug (was returning OK_Orig in some cases). Fix return subtype to
	clarify that it can only return OK or Abandon.

	* sem_res.adb (Resolve_Op_Concat): Replace the recursion on the left
	operand by iteration, in order to avoid running out of memory on
	deeply-nested concatenations. Use the Parent pointer to get back up the
	tree.
	(Resolve_Op_Concat_Arg, Resolve_Op_Concat_First,
	 Resolve_Op_Concat_Rest): New procedures split out of
	Resolve_Op_Concat, so the iterative algorithm in Resolve_Op_Concat is
	clearer.

	* checks.adb (Remove_Checks): Use Traverse_Proc instead of
	Traverse_Func, because the former already takes care of discarding the
	result.

	* errout.adb (First_Node): Use Traverse_Proc instead of Traverse_Func,
	because the former already takes care of discarding the result.
	(Remove_Warning_Messages): Use appropriate subtype for Status and
	Discard

From-SVN: r131070
parent 160df979
...@@ -2624,12 +2624,12 @@ package body Atree is ...@@ -2624,12 +2624,12 @@ package body Atree is
-- Traverse_Func -- -- Traverse_Func --
------------------- -------------------
function Traverse_Func (Node : Node_Id) return Traverse_Result is function Traverse_Func (Node : Node_Id) return Traverse_Final_Result is
function Traverse_Field function Traverse_Field
(Nod : Node_Id; (Nod : Node_Id;
Fld : Union_Id; Fld : Union_Id;
FN : Field_Num) return Traverse_Result; FN : Field_Num) return Traverse_Final_Result;
-- Fld is one of the fields of Nod. If the field points to syntactic -- Fld is one of the fields of Nod. If the field points to syntactic
-- node or list, then this node or list is traversed, and the result is -- node or list, then this node or list is traversed, and the result is
-- the result of this traversal. Otherwise a value of True is returned -- the result of this traversal. Otherwise a value of True is returned
...@@ -2642,7 +2642,7 @@ package body Atree is ...@@ -2642,7 +2642,7 @@ package body Atree is
function Traverse_Field function Traverse_Field
(Nod : Node_Id; (Nod : Node_Id;
Fld : Union_Id; Fld : Union_Id;
FN : Field_Num) return Traverse_Result FN : Field_Num) return Traverse_Final_Result
is is
begin begin
if Fld = Union_Id (Empty) then if Fld = Union_Id (Empty) then
...@@ -2697,10 +2697,21 @@ package body Atree is ...@@ -2697,10 +2697,21 @@ package body Atree is
end if; end if;
end Traverse_Field; end Traverse_Field;
Cur_Node : Node_Id := Node;
-- Start of processing for Traverse_Func -- Start of processing for Traverse_Func
begin begin
case Process (Node) is -- We walk Field2 last, and if it is a node, we eliminate the tail
-- recursion by jumping back to this label. This is because Field2 is
-- where the Left_Opnd field of N_Op_Concat is stored, and in practice
-- concatenations are sometimes deeply nested, as in X1&X2&...&XN. This
-- trick prevents us from running out of memory in that case. We don't
-- bother eliminating the tail recursion if Field2 is a list.
<<Tail_Recurse>>
case Process (Cur_Node) is
when Abandon => when Abandon =>
return Abandon; return Abandon;
...@@ -2708,41 +2719,37 @@ package body Atree is ...@@ -2708,41 +2719,37 @@ package body Atree is
return OK; return OK;
when OK => when OK =>
if Traverse_Field (Node, Union_Id (Field1 (Node)), 1) = Abandon null;
or else
Traverse_Field (Node, Union_Id (Field2 (Node)), 2) = Abandon
or else
Traverse_Field (Node, Union_Id (Field3 (Node)), 3) = Abandon
or else
Traverse_Field (Node, Union_Id (Field4 (Node)), 4) = Abandon
or else
Traverse_Field (Node, Union_Id (Field5 (Node)), 5) = Abandon
then
return Abandon;
else
return OK;
end if;
when OK_Orig => when OK_Orig =>
declare Cur_Node := Original_Node (Cur_Node);
Onod : constant Node_Id := Original_Node (Node);
begin
if Traverse_Field (Onod, Union_Id (Field1 (Onod)), 1) = Abandon
or else
Traverse_Field (Onod, Union_Id (Field2 (Onod)), 2) = Abandon
or else
Traverse_Field (Onod, Union_Id (Field3 (Onod)), 3) = Abandon
or else
Traverse_Field (Onod, Union_Id (Field4 (Onod)), 4) = Abandon
or else
Traverse_Field (Onod, Union_Id (Field5 (Onod)), 5) = Abandon
then
return Abandon;
else
return OK_Orig;
end if;
end;
end case; end case;
if Traverse_Field (Cur_Node, Field1 (Cur_Node), 1) = Abandon
or else -- skip Field2 here
Traverse_Field (Cur_Node, Field3 (Cur_Node), 3) = Abandon
or else
Traverse_Field (Cur_Node, Field4 (Cur_Node), 4) = Abandon
or else
Traverse_Field (Cur_Node, Field5 (Cur_Node), 5) = Abandon
then
return Abandon;
end if;
if Field2 (Cur_Node) not in Node_Range then
return Traverse_Field (Cur_Node, Field2 (Cur_Node), 2);
elsif Is_Syntactic_Field (Nkind (Cur_Node), 2) and then
Field2 (Cur_Node) /= Empty_List_Or_Node
then
-- Here is the tail recursion step, we reset Cur_Node and jump
-- back to the start of the procedure, which has the same
-- semantic effect as a call.
Cur_Node := Node_Id (Field2 (Cur_Node));
goto Tail_Recurse;
end if;
return OK;
end Traverse_Func; end Traverse_Func;
------------------- -------------------
...@@ -2751,7 +2758,7 @@ package body Atree is ...@@ -2751,7 +2758,7 @@ package body Atree is
procedure Traverse_Proc (Node : Node_Id) is procedure Traverse_Proc (Node : Node_Id) is
function Traverse is new Traverse_Func (Process); function Traverse is new Traverse_Func (Process);
Discard : Traverse_Result; Discard : Traverse_Final_Result;
pragma Warnings (Off, Discard); pragma Warnings (Off, Discard);
begin begin
Discard := Traverse (Node); Discard := Traverse (Node);
......
...@@ -503,18 +503,22 @@ package Atree is ...@@ -503,18 +503,22 @@ package Atree is
-- function is used only by Sinfo.CN to change nodes into their -- function is used only by Sinfo.CN to change nodes into their
-- corresponding entities. -- corresponding entities.
type Traverse_Result is (OK, OK_Orig, Skip, Abandon); type Traverse_Result is (Abandon, OK, OK_Orig, Skip);
-- This is the type of the result returned by the Process function passed -- This is the type of the result returned by the Process function passed
-- to Traverse_Func and Traverse_Proc and also the type of the result of -- to Traverse_Func and Traverse_Proc. See below for details.
-- Traverse_Func itself. See descriptions below for details.
subtype Traverse_Final_Result is Traverse_Result range Abandon .. OK;
-- This is the type of the final result returned Traverse_Func, based on
-- the results of Process calls. See below for details.
generic generic
with function Process (N : Node_Id) return Traverse_Result is <>; with function Process (N : Node_Id) return Traverse_Result is <>;
function Traverse_Func (Node : Node_Id) return Traverse_Result; function Traverse_Func (Node : Node_Id) return Traverse_Final_Result;
-- This is a generic function that, given the parent node for a subtree, -- This is a generic function that, given the parent node for a subtree,
-- traverses all syntactic nodes of this tree, calling the given function -- traverses all syntactic nodes of this tree, calling the given function
-- Process on each one. The traversal is controlled as follows by the -- Process on each one, in pre order (i.e. top-down). The order of
-- result returned by Process: -- traversing subtrees is arbitrary. The traversal is controlled as follows
-- by the result returned by Process:
-- OK The traversal continues normally with the syntactic -- OK The traversal continues normally with the syntactic
-- children of the node just processed. -- children of the node just processed.
...@@ -537,7 +541,7 @@ package Atree is ...@@ -537,7 +541,7 @@ package Atree is
with function Process (N : Node_Id) return Traverse_Result is <>; with function Process (N : Node_Id) return Traverse_Result is <>;
procedure Traverse_Proc (Node : Node_Id); procedure Traverse_Proc (Node : Node_Id);
pragma Inline (Traverse_Proc); pragma Inline (Traverse_Proc);
-- This is similar to Traverse_Func except that no result is returned, -- This is the same as Traverse_Func except that no result is returned,
-- i.e. Traverse_Func is called and the result is simply discarded. -- i.e. Traverse_Func is called and the result is simply discarded.
--------------------------- ---------------------------
......
...@@ -2360,7 +2360,6 @@ package body Checks is ...@@ -2360,7 +2360,6 @@ package body Checks is
Analyze_And_Resolve (N, Typ); Analyze_And_Resolve (N, Typ);
return; return;
end if; end if;
end Apply_Universal_Integer_Attribute_Checks; end Apply_Universal_Integer_Attribute_Checks;
------------------------------- -------------------------------
...@@ -5366,14 +5365,11 @@ package body Checks is ...@@ -5366,14 +5365,11 @@ package body Checks is
------------------- -------------------
procedure Remove_Checks (Expr : Node_Id) is procedure Remove_Checks (Expr : Node_Id) is
Discard : Traverse_Result;
pragma Warnings (Off, Discard);
function Process (N : Node_Id) return Traverse_Result; function Process (N : Node_Id) return Traverse_Result;
-- Process a single node during the traversal -- Process a single node during the traversal
function Traverse is new Traverse_Func (Process); procedure Traverse is new Traverse_Proc (Process);
-- The traversal function itself -- The traversal procedure itself
------------- -------------
-- Process -- -- Process --
...@@ -5389,7 +5385,7 @@ package body Checks is ...@@ -5389,7 +5385,7 @@ package body Checks is
case Nkind (N) is case Nkind (N) is
when N_And_Then => when N_And_Then =>
Discard := Traverse (Left_Opnd (N)); Traverse (Left_Opnd (N));
return Skip; return Skip;
when N_Attribute_Reference => when N_Attribute_Reference =>
...@@ -5425,7 +5421,7 @@ package body Checks is ...@@ -5425,7 +5421,7 @@ package body Checks is
end case; end case;
when N_Or_Else => when N_Or_Else =>
Discard := Traverse (Left_Opnd (N)); Traverse (Left_Opnd (N));
return Skip; return Skip;
when N_Selected_Component => when N_Selected_Component =>
...@@ -5446,7 +5442,7 @@ package body Checks is ...@@ -5446,7 +5442,7 @@ package body Checks is
-- Start of processing for Remove_Checks -- Start of processing for Remove_Checks
begin begin
Discard := Traverse (Expr); Traverse (Expr);
end Remove_Checks; end Remove_Checks;
---------------------------- ----------------------------
......
...@@ -1235,15 +1235,12 @@ package body Errout is ...@@ -1235,15 +1235,12 @@ package body Errout is
Sfile : constant Source_File_Index := Get_Source_File_Index (L); Sfile : constant Source_File_Index := Get_Source_File_Index (L);
Earliest : Node_Id; Earliest : Node_Id;
Eloc : Source_Ptr; Eloc : Source_Ptr;
Discard : Traverse_Result;
pragma Warnings (Off, Discard);
function Test_Earlier (N : Node_Id) return Traverse_Result; function Test_Earlier (N : Node_Id) return Traverse_Result;
-- Function applied to every node in the construct -- Function applied to every node in the construct
function Search_Tree_First is new Traverse_Func (Test_Earlier); procedure Search_Tree_First is new Traverse_Proc (Test_Earlier);
-- Create traversal function -- Create traversal procedure
------------------ ------------------
-- Test_Earlier -- -- Test_Earlier --
...@@ -1273,7 +1270,7 @@ package body Errout is ...@@ -1273,7 +1270,7 @@ package body Errout is
begin begin
Earliest := Original_Node (C); Earliest := Original_Node (C);
Eloc := Sloc (Earliest); Eloc := Sloc (Earliest);
Discard := Search_Tree_First (Original_Node (C)); Search_Tree_First (Original_Node (C));
return Earliest; return Earliest;
end First_Node; end First_Node;
...@@ -1982,7 +1979,7 @@ package body Errout is ...@@ -1982,7 +1979,7 @@ package body Errout is
-- to the tree is harmless. -- to the tree is harmless.
declare declare
Status : Traverse_Result; Status : Traverse_Final_Result;
begin begin
if Is_List_Member (N) then if Is_List_Member (N) then
...@@ -2006,7 +2003,7 @@ package body Errout is ...@@ -2006,7 +2003,7 @@ package body Errout is
begin begin
if Warnings_Detected /= 0 then if Warnings_Detected /= 0 then
declare declare
Discard : Traverse_Result; Discard : Traverse_Final_Result;
pragma Warnings (Off, Discard); pragma Warnings (Off, Discard);
begin begin
......
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