diff options
Diffstat (limited to 'gcc/ada/exp_util.adb')
| -rw-r--r-- | gcc/ada/exp_util.adb | 326 | 
1 files changed, 187 insertions, 139 deletions
diff --git a/gcc/ada/exp_util.adb b/gcc/ada/exp_util.adb index 4d88626..e2d2554 100644 --- a/gcc/ada/exp_util.adb +++ b/gcc/ada/exp_util.adb @@ -7317,6 +7317,134 @@ package body Exp_Util is        Loc : constant Source_Ptr := Sloc (Var);        Ent : constant Entity_Id  := Entity (Var); +      procedure Find_In_Enclosing_Context +        (Stmt : Node_Id; Current, Previous : in out Node_Id); +      --  Locate an object reference inside a composite statement Stmt. On +      --  entry, Previous and Current should be an object reference and its +      --  parent, respectively. When search is successful, Current is Stmt and +      --  Previous is its child node, so the caller can determine in which part +      --  of the statement the original reference was. When search fails, both +      --  Current and Previous are Empty. + +      function Is_Transient_Action (N : Node_Id) return Boolean; +      --  Returns True for nodes that belong to a transient action and so they +      --  have no parent, because they have not been inserted to the tree yet. + +      ------------------------------- +      -- Find_In_Enclosing_Context -- +      ------------------------------- + +      procedure Find_In_Enclosing_Context +        (Stmt : Node_Id; Current, Previous : in out Node_Id) +      is +      begin +         loop +            --  If we fall off the top of the tree, then that's odd, but +            --  perhaps it could occur in some error situation, and the safest +            --  response is simply to assume that the outcome of the condition +            --  is unknown. No point in bombing during an attempt to optimize +            --  things. + +            if No (Current) then + +               --  In particular, we expect to miss the enclosing conditional +               --  statement for: +               --  * references within a freezing action (because their +               --    location is unrelated to the conditional statement), +               --  * validity checks (becuase for references inside the +               --    condition they are inserted before the conditional +               --    statement itself), +               --  * source locations before and after the conditionaal +               --    statement. + +               pragma Assert +                 (Inside_Freezing_Actions > 0 +                  or else +                    (Ekind (Entity (Var)) = E_Variable +                     and then Present (Validated_Object (Entity (Var)))) +                  or else +                    Loc < Sloc (Stmt) +                  or else +                    Loc >= Sloc (Stmt) + Text_Ptr (UI_To_Int (End_Span (Stmt))) +                  or else +                    Serious_Errors_Detected > 0); + +               return; + +            --  We found the enclosing conditional statement + +            elsif Current = Stmt then +               return; + +            --  For itype declarations follow their associated node + +            elsif Nkind (Current) = N_Subtype_Declaration +              and then Is_Itype (Defining_Identifier (Current)) +            then +               Previous := Current; +               Current := +                 Associated_Node_For_Itype (Defining_Identifier (Previous)); + +               --  If associated node has not been set yet, we can use the +               --  related expression, which is set earlier. +               --  ??? this should be investigated + +               if No (Current) then +                  Current := +                    Related_Expression (Defining_Identifier (Previous)); +               end if; +               pragma Assert (Present (Current)); + +            --  Same for itypes that have no declaration + +            elsif Nkind (Current) = N_Defining_Identifier +              and then Is_Itype (Current) +            then +               pragma Assert (No (Parent (Current))); +               Previous := Current; +               Current := Associated_Node_For_Itype (Previous); + +            --  For transient actions follow where they will be inserted + +            elsif Is_Transient_Action (Current) then +               Previous := Current; +               Current := +                 Scope_Stack.Table (Scope_Stack.Last).Node_To_Be_Wrapped; + +            --  Otherwise, continue climbing + +            else +               Previous := Current; +               Current := Parent (Current); +            end if; +         end loop; +      end Find_In_Enclosing_Context; + +      ------------------------- +      -- Is_Transient_Action -- +      ------------------------- + +      function Is_Transient_Action (N : Node_Id) return Boolean is +      begin +         if Scope_Stack.Last >= Scope_Stack.First +           and then Scope_Is_Transient +           and then Is_List_Member (N) +         then +            declare +               Transient_Actions : Scope_Actions renames +                 Scope_Stack.Table (Scope_Stack.Last).Actions_To_Be_Wrapped; +            begin +               for Action_Kind in Scope_Actions'Range loop +                  if List_Containing (N) = Transient_Actions (Action_Kind) then +                     return True; +                  end if; +               end loop; +            end; +         end if; + +         return False; +      end Is_Transient_Action; +        procedure Process_Current_Value_Condition (N : Node_Id; S : Boolean);        --  N is an expression which holds either True (S = True) or False (S =        --  False) in the condition. This procedure digs out the expression and @@ -7490,156 +7618,71 @@ package body Exp_Util is        declare           CV   : constant Node_Id := Current_Value (Ent);           Sens : Boolean; -         Stm  : Node_Id;        begin -         --  If statement. Condition is known true in THEN section, known False -         --  in any ELSIF or ELSE part, and unknown outside the IF statement. - -         if Nkind (CV) = N_If_Statement then +         --  For IF statement the condition is known true in THEN section, +         --  known False in any ELSIF or ELSE part, and unknown outside the +         --  IF statement. -            --  Before start of IF statement - -            if Loc < Sloc (CV) then -               return; - -            --  In condition of IF statement - -            elsif In_Subtree (N => Var, Root => Condition (CV)) then -               return; +         if Nkind (CV) in N_If_Statement | N_Elsif_Part then -            --  After end of IF statement - -            elsif Loc >= Sloc (CV) + Text_Ptr (UI_To_Int (End_Span (CV))) then -               return; -            end if; - -            --  At this stage we know that we are within the IF statement, but -            --  unfortunately, the tree does not record the SLOC of the ELSE so -            --  we cannot use a simple SLOC comparison to distinguish between -            --  the then/else statements, so we have to climb the tree. +            --  At this stage we know that we are within the conditional +            --  statement, but we have to climb the tree to know in which +            --  part, e.g. in THEN or ELSE statements of an IF statement.              declare -               N : Node_Id; - -            begin -               N := Parent (Var); -               while Parent (N) /= CV loop -                  N := Parent (N); +               If_Stmt : constant Node_Id := +                 (if Nkind (CV) = N_If_Statement +                  then CV +                  else Parent (CV)); -                  --  If we fall off the top of the tree, then that's odd, but -                  --  perhaps it could occur in some error situation, and the -                  --  safest response is simply to assume that the outcome of -                  --  the condition is unknown. No point in bombing during an -                  --  attempt to optimize things. +               Previous : Node_Id := Var; +               Current  : Node_Id := Parent (Var); -                  if No (N) then -                     return; -                  end if; -               end loop; - -               --  Now we have N pointing to a node whose parent is the IF -               --  statement in question, so now we can tell if we are within -               --  the THEN statements. - -               if Is_List_Member (N) -                 and then List_Containing (N) = Then_Statements (CV) -               then -                  Sens := True; - -               --  If the variable reference does not come from source, we -               --  cannot reliably tell whether it appears in the else part. -               --  In particular, if it appears in generated code for a node -               --  that requires finalization, it may be attached to a list -               --  that has not been yet inserted into the code. For now, -               --  treat it as unknown. +            begin +               --  An ELSIF part whose condition is false could have been +               --  already rewritten into NULL statement and we are already +               --  past the statements inside that ELSIF part. -               elsif not Comes_From_Source (N) then +               if Nkind (If_Stmt) /= N_If_Statement then +                  pragma Assert +                    (Nkind (CV) = N_Elsif_Part +                     and then Is_Rewrite_Substitution (If_Stmt));                    return; - -               --  Otherwise we must be in ELSIF or ELSE part - -               else -                  Sens := False;                 end if; -            end; -            --  ELSIF part. Condition is known true within the referenced -            --  ELSIF, known False in any subsequent ELSIF or ELSE part, -            --  and unknown before the ELSE part or after the IF statement. - -         elsif Nkind (CV) = N_Elsif_Part then - -            --  if the Elsif_Part had condition_actions, the elsif has been -            --  rewritten as a nested if, and the original elsif_part is -            --  detached from the tree, so there is no way to obtain useful -            --  information on the current value of the variable. -            --  Can this be improved ??? - -            if No (Parent (CV)) then -               return; -            end if; - -            Stm := Parent (CV); - -            --  If the tree has been otherwise rewritten there is nothing -            --  else to be done either. - -            if Nkind (Stm) /= N_If_Statement then -               return; -            end if; - -            --  Before start of ELSIF part - -            if Loc < Sloc (CV) then -               return; +               Find_In_Enclosing_Context (If_Stmt, Current, Previous); -            --  In condition of ELSIF part - -            elsif In_Subtree (N => Var, Root => Condition (CV)) then -               return; - -            --  After end of IF statement +               --  Check whether the reference is in the IF, THEN or ELSE/ELSIF +               --  part. -            elsif Loc >= Sloc (Stm) + -              Text_Ptr (UI_To_Int (End_Span (Stm))) -            then -               return; -            end if; +               if Current = If_Stmt then -            --  Again we lack the SLOC of the ELSE, so we need to climb the -            --  tree to see if we are within the ELSIF part in question. +                  --  Ignore references from within the IF condition itself -            declare -               N : Node_Id; +                  if Previous = Condition (If_Stmt) then +                     return; -            begin -               N := Parent (Var); -               while Parent (N) /= Stm loop -                  N := Parent (N); +                  --  Guard against if-statements coming from if-statements +                  --  with broken chain of parents. -                  --  If we fall off the top of the tree, then that's odd, but -                  --  perhaps it could occur in some error situation, and the -                  --  safest response is simply to assume that the outcome of -                  --  the condition is unknown. No point in bombing during an -                  --  attempt to optimize things. +                  elsif Is_List_Member (Previous) then +                     pragma Assert ( +                       List_Containing (Previous) +                          in Then_Statements (If_Stmt) +                           | Elsif_Parts (If_Stmt) +                           | Else_Statements (If_Stmt)); -                  if No (N) then +                     Sens := +                       (if CV = If_Stmt +                        then List_Containing (Previous) = Then_Statements (CV) +                        else Previous = CV); +                  else +                     pragma Assert (From_Conditional_Expression (If_Stmt));                       return;                    end if; -               end loop; - -               --  Now we have N pointing to a node whose parent is the IF -               --  statement in question, so see if is the ELSIF part we want. -               --  the THEN statements. - -               if N = CV then -                  Sens := True; - -                  --  Otherwise we must be in subsequent ELSIF or ELSE part -                 else -                  Sens := False; +                  return;                 end if;              end; @@ -7650,26 +7693,31 @@ package body Exp_Util is              declare                 Loop_Stmt : constant Node_Id := Parent (CV); +               Previous : Node_Id := Var; +               Current  : Node_Id := Parent (Var); +              begin -               --  Before start of body of loop +               pragma Assert (Nkind (Loop_Stmt) = N_Loop_Statement); -               if Loc < Sloc (Loop_Stmt) then -                  return; +               Find_In_Enclosing_Context (Loop_Stmt, Current, Previous); -               --  In condition of while loop +               --  Check whether the reference is inside the WHILE loop -               elsif In_Subtree (N => Var, Root => Condition (CV)) then -                  return; +               if Current = Loop_Stmt then -               --  After end of LOOP statement +                  --  Ignore references from within the WHILE condition itself -               elsif Loc >= Sloc (End_Label (Loop_Stmt)) then -                  return; +                  if Previous = Iteration_Scheme (Loop_Stmt) then +                     return; -               --  We are within the body of the loop +                  else +                     pragma Assert +                       (List_Containing (Previous) = Statements (Loop_Stmt)); +                     Sens := True; +                  end if;                 else -                  Sens := True; +                  return;                 end if;              end;  | 
