From: Tucker Taft <t...@adacore.com>

In the Expression_Image function, we were not inserting
parentheses properly when there was a sequence of
and and or operators, even though Ada requires such
parentheses to show the correct order of association.

gcc/ada/ChangeLog:

        * pprint.adb (Expression_Image): In local function Expr_Name
        add a No_Parens flag and define a subtype Not_Associative
        to represent the short-circuit operations and And/Or/Xor.
        Insert parentheses to separate the subexpressions when
        different "Not_Associative" operations occur in a
        sequence.

Tested on x86_64-pc-linux-gnu, committed on master.

---
 gcc/ada/pprint.adb | 53 ++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 46 insertions(+), 7 deletions(-)

diff --git a/gcc/ada/pprint.adb b/gcc/ada/pprint.adb
index b5935fcb0b4..5958a6b47b2 100644
--- a/gcc/ada/pprint.adb
+++ b/gcc/ada/pprint.adb
@@ -57,12 +57,16 @@ package body Pprint is
       function Expr_Name
         (Expr        : Node_Id;
          Take_Prefix : Boolean := True;
-         Expand_Type : Boolean := True) return String;
+         Expand_Type : Boolean := True;
+         No_Parens   : Boolean := False) return String;
       --  Return string corresponding to Expr. If no string can be extracted,
       --  return "...". If Take_Prefix is True, go back to prefix when needed,
       --  otherwise only consider the right-hand side of an expression. If
       --  Expand_Type is True and Expr is a type, try to expand Expr (an
       --  internally generated type) into a user understandable name.
+      --  If No_Parens is True, then suppress creating parentheses
+      --  around expression.  If False, check to see whether expression
+      --  should be parenthesized.
 
       function Count_Parentheses (S : String; C : Character) return Natural
         with Pre => C in '(' | ')';
@@ -70,6 +74,8 @@ package body Pprint is
       --  to string S for getting a correctly parenthesized result. For C = '('
       --  this means prepending the character, for C = ')' this means appending
       --  the character.
+      --  In other words, count the number of missing instances of C,
+      --  but never return less than zero.
 
       function Fix_Parentheses (S : String) return String;
       --  Counts the number of required opening and closing parentheses in S to
@@ -101,6 +107,7 @@ package body Pprint is
          Elmt : Node_Id;
 
          Printed_Elmts : Natural := 0;
+         List_Len : constant Natural := Natural (List_Length (List));
 
       begin
          --  Give up if the printed list is too deep
@@ -146,7 +153,8 @@ package body Pprint is
             --  Print expression itself as "12345"
 
             else
-               Append (Buf, Expr_Name (Elmt));
+               Append (Buf, Expr_Name (Elmt, No_Parens => List_Len = 1));
+                  --  Suppress parens if is the only parameter.
             end if;
 
             Next (Elmt);
@@ -178,9 +186,32 @@ package body Pprint is
       function Expr_Name
         (Expr        : Node_Id;
          Take_Prefix : Boolean := True;
-         Expand_Type : Boolean := True) return String
+         Expand_Type : Boolean := True;
+         No_Parens   : Boolean := False) return String
       is
+         --  Define subtype matching logical operations
+         --  and [then], or [else], and xor.
+         subtype Not_Associative is N_Subexpr
+           with Static_Predicate =>
+             Not_Associative in
+               N_Short_Circuit | N_Op_And | N_Op_Or | N_Op_Xor;
       begin
+         if not No_Parens
+          and then
+            (Paren_Count (Expr) > 0
+              or else
+             (Nkind (Expr) in Not_Associative
+               and then
+              Nkind (Parent (Expr)) in Not_Associative
+               and then
+              Nkind (Parent (Expr)) /= Nkind (Expr)))
+         then
+            --  Parentheses are needed
+            return '(' &
+              Expr_Name (Expr, Take_Prefix, Expand_Type, No_Parens => True) &
+              ')';
+         end if;
+
          Num_Elements := Num_Elements + 1;
 
          if Num_Elements > Max_Expr_Elements then
@@ -589,7 +620,9 @@ package body Pprint is
                return "abs " & Expr_Name (Right_Opnd (Expr));
 
             when N_Op_Not =>
-               return "not (" & Expr_Name (Right_Opnd (Expr)) & ")";
+               return "not (" &
+                      Expr_Name (Right_Opnd (Expr), No_Parens => True) &
+                      ")";
 
             when N_Type_Conversion =>
 
@@ -608,7 +641,9 @@ package body Pprint is
                            Is_Modular_Integer_Type (Etype (Expression (Expr)))
                then
                   return Expr_Name (Subtype_Mark (Expr)) &
-                    "(" & Expr_Name (Expression (Expr)) & ")";
+                    "(" &
+                    Expr_Name (Expression (Expr), No_Parens => True) &
+                    ")";
                else
                   return Expr_Name (Expression (Expr));
                end if;
@@ -636,7 +671,9 @@ package body Pprint is
                        & List_Name (Parameter_Associations (Expr))
                        & "))";
                   else
-                     return '(' & Expr_Name (Name (Expr)) & ')';
+                     return '(' &
+                             Expr_Name (Name (Expr), No_Parens => True) &
+                             ')';
                   end if;
                elsif Present (Parameter_Associations (Expr)) then
                   return
@@ -676,6 +713,8 @@ package body Pprint is
          --  Process next character Ch and update the number Count of C
          --  characters to add for correct parenthesizing, where D is the
          --  opposite parenthesis.
+         --  In other words, count the number of missing instances of C,
+         --  or equivalently, the number of unmatched instances of D.
 
          ---------------
          -- Next_Char --
@@ -775,7 +814,7 @@ package body Pprint is
         or else Opt.Debug_Generated_Code
       then
          declare
-            S : constant String := Expr_Name (Expr);
+            S : constant String := Expr_Name (Expr, No_Parens => True);
          begin
             if S = "..." then
                return Default;
-- 
2.43.0

Reply via email to