[Ada] Implement static predicates for string/real types

Arnaud Charlet charlet@adacore.com
Tue Jul 29 13:54:00 GMT 2014


This implements static predicates for string and real types,
as defined in the RM. There is one exception, which is that
the RM allows X > "ABC" as being predicate static, but since
"ABC" > "ABA" is not static, that's peculiar, so we assume
that this is a mistake in the RM, and that string comparisons
should not be permitted as predicate-static.

The following test program shows various uses of static
predicates of all types with a range of legality tests
and tests for compile time evaluation of static predicates.

     1. package TestSP is
     2.    subtype F1 is Float with -- OK
     3.    Static_Predicate => F1 > 0.0 and 4.7 > F1;
     4.
     5.    subtype F1a is F1 with -- OK
     6.      Static_Predicate => F1a > 2.4;
     7.
     8.    subtype F2 is Float with -- ERROR
     9.      Static_Predicate => (F2 + 1.0) > 0.0 and 4.7 > F2;
                                  |
        >>> expression is not predicate-static (RM 4.3.2(16-22))

    10.    subtype F3 is Float with -- OK
    11.      Dynamic_Predicate => (F3 + 1.0) > 0.0 and 4.7 > F3;
    12.    subtype F4 is Float with -- OK
    13.      Predicate => (F4 + 1.0) > 0.0 and 4.7 > F4;
    14.
    15.    subtype S0 is String with -- ERROR
    16.      Static_Predicate => S0 > "ABC" and then "DEF" >= S0;
                                 |
        >>> expression is not predicate-static (RM 4.3.2(16-22))

    17.    subtype S1 is String with -- OK
    18.      Static_Predicate => S1 in "ABC" | "DEF";
    19.
    20.    subtype S2 is String with -- ERROR
    21.      Static_Predicate => S2'First = 1 and then S2(1) = 'A';
                                 |
        >>> expression is not predicate-static (RM 4.3.2(16-22))

    22.    subtype S3 is String with -- OK
    23.      Dynamic_Predicate => S3'First = 1 and then S3(1) = 'A';
    24.    subtype S4 is String with -- OK
    25.      Predicate => S4'First = 1 and then S4(1) = 'A';
    26.    subtype S5 is String with -- OK
    27.      Predicate => S5 in "ABC" | "DEF";
    28.    subtype S6 is String with -- OK
    29.      Dynamic_Predicate => S6 in "ABC" | "DEF";
    30.
    31.    subtype I1 is Integer with -- OK
    32.      Static_Predicate => I1 > 0 and 4 > I1;
    33.    subtype I1a is I1 with -- OK
    34.      Static_Predicate => I1a > 2;
    35.
    36.    subtype I2 is Integer with -- ERROR
    37.      Static_Predicate => (I2 + 1) > 0 and 4 > I2;
                                  |
        >>> expression is not predicate-static (RM 4.3.2(16-22))

    38.    subtype I3 is Integer with -- OK
    39.      Dynamic_Predicate => (I3 + 1) > 0 and 4 > I3;
    40.    subtype I4 is Integer with -- OK
    41.      Predicate => (I4 + 1) > 0 and 4 > I4;
    42.
    43.    subtype I5 is Integer with -- ERROR
    44.      Static_Predicate => Boolean'(I5 > 0);
                                 |
        >>> expression is not predicate-static (RM 4.3.2(16-22))

    45.
    46.    XF1 : constant F1 := 10.0; -- WARN
                                |
        >>> warning: static expression fails static predicate
            check on "F1", expression is no longer considered
            static

    47.    XF2 : constant F1 := 3.0;  -- OK
    48.
    49.    XF3 : constant := XF1;     -- ERROR
                             |
        >>> non-static expression used in number declaration
        >>> "XF1" is not a static constant (RM 4.9(5))

    50.    XF4 : constant := XF2;     -- OK
    51.
    52.    XF1a : constant F1a := 1.3; -- WARN;
                                  |
        >>> warning: static expression fails static predicate
            check on "F1a", expression is no longer considered
            static

    53.    XF1b : constant F1a := 5.3; -- WARN;
                                  |
        >>> warning: static expression fails static predicate
            check on "F1a", expression is no longer considered
            static

    54.    XF1c : constant F1a := 3.7; -- OK
    55.
    56.    XI1 : constant I1 := 10; -- WARN
                                |
        >>> warning: static expression fails static predicate
            check on "I1", expression is no longer considered
            static

    57.    XI2 : constant I1 := 3;  -- OK
    58.
    59.    XI3 : constant := XI1;   -- ERROR
                             |
        >>> non-static expression used in number declaration
        >>> "XI1" is not a static constant (RM 4.9(5))

    60.    XI4 : constant := XI2;   -- OK
    61.
    62.    XI1a : constant I1a := 2; -- WARN
                                  |
        >>> warning: static expression fails static predicate
            check on "I1a", expression is no longer considered
            static

    63.    XI1b : constant I1a := 7; -- WARN
                                  |
        >>> warning: static expression fails static predicate
            check on "I1a", expression is no longer considered
            static

    64.    XI1c : constant I1a := 3; -- OK
    65.
    66.    XSa : constant S1 := "ABC"; -- OK
    67.
    68.    Xsb : constant S1 := "DQR"; -- WARN
                                |
        >>> warning: static expression fails static predicate
            check on "S1", expression is no longer considered
            static

    69.    XSc : constant S5 := "ABC"; -- OK
    70.
    71.    Xsd : constant S5 := "DQR"; -- WARN
                                |
        >>> warning: static expression fails static predicate
            check on "S5", expression is no longer considered
            static

    72.    Xse : constant S6 := "ABC"; -- OK
    73.
    74.    Xsf : constant S6 := "DQR"; -- WARN
                                |
        >>> warning: expression fails predicate check on "S6"

    75. end;

Tested on x86_64-pc-linux-gnu, committed on trunk

2014-07-29  Robert Dewar  <dewar@adacore.com>

	* einfo.ads, einfo.adb (Static_Real_Or_String_Predicate): New function
	(Set_Static_Real_Or_String_Predicate): New procedure
	* sem_ch13.adb (Build_Predicate_Functions): Accomodate static
	string predicates (Is_Predicate_Static): Handle static string
	predicates.
	* sem_eval.adb (Real_Or_String_Static_Predicate_Matches):
	New procedure (Check_Expression_Against_Static_Predicate):
	Deal with static string predicates, now fully implemented
	(Eval_Relational_Op): Allow string equality/inequality as static
	if not comes from source.

-------------- next part --------------
Index: einfo.adb
===================================================================
--- einfo.adb	(revision 213161)
+++ einfo.adb	(revision 213162)
@@ -223,6 +223,7 @@
    --    PPC_Wrapper                     Node25
    --    Related_Array_Object            Node25
    --    Static_Discrete_Predicate       List25
+   --    Static_Real_Or_String_Predicate Node25
    --    Task_Body_Procedure             Node25
 
    --    Dispatch_Table_Wrappers         Elist26
@@ -2977,6 +2978,12 @@
       return List25 (Id);
    end Static_Discrete_Predicate;
 
+   function Static_Real_Or_String_Predicate (Id : E) return N is
+   begin
+      pragma Assert (Is_Real_Type (Id) or else Is_String_Type (Id));
+      return Node25 (Id);
+   end Static_Real_Or_String_Predicate;
+
    function Status_Flag_Or_Transient_Decl (Id : E) return N is
    begin
       pragma Assert (Ekind_In (Id, E_Constant, E_Variable));
@@ -5767,6 +5774,13 @@
       Set_List25 (Id, V);
    end Set_Static_Discrete_Predicate;
 
+   procedure Set_Static_Real_Or_String_Predicate (Id : E; V : N) is
+   begin
+      pragma Assert ((Is_Real_Type (Id) or else Is_String_Type (Id))
+                      and then Has_Predicates (Id));
+      Set_Node25 (Id, V);
+   end Set_Static_Real_Or_String_Predicate;
+
    procedure Set_Status_Flag_Or_Transient_Decl (Id : E; V : E) is
    begin
       pragma Assert (Ekind_In (Id, E_Constant, E_Variable));
@@ -9399,13 +9413,12 @@
               E_Entry_Family                               =>
             Write_Str ("PPC_Wrapper");
 
-         when E_Enumeration_Type                           |
-              E_Enumeration_Subtype                        |
-              E_Modular_Integer_Type                       |
-              E_Modular_Integer_Subtype                    |
-              E_Signed_Integer_Subtype                     =>
+         when Discrete_Kind                                =>
             Write_Str ("Static_Discrete_Predicate");
 
+         when Real_Kind                                    =>
+            Write_Str ("Static_Real_Or_String_Predicate");
+
          when others                                       =>
             Write_Str ("Field25??");
       end case;
Index: einfo.ads
===================================================================
--- einfo.ads	(revision 213161)
+++ einfo.ads	(revision 213162)
@@ -3899,7 +3899,7 @@
 
 --    Static_Discrete_Predicate (List25)
 --       Defined in discrete types/subtypes with static predicates (with the
---       two flags Has_Predicates set and Has_Static_Predicate set). Set if the
+--       two flags Has_Predicates and Has_Static_Predicate set). Set if the
 --       type/subtype has a static predicate. Points to a list of expression
 --       and N_Range nodes that represent the predicate in canonical form. The
 --       canonical form has entries sorted in ascending order, with duplicates
@@ -3908,6 +3908,26 @@
 --       are fully analyzed and typed with the base type of the subtype. Note
 --       that all entries are static and have values within the subtype range.
 
+--    Static_Real_Or_String_Predicate (Node25)
+--       Defined in real types/subtypes with static predicates (with the two
+--       flags Has_Predicates and Has_Static_Predicate set). Set if the type
+--       or subtype has a static predicate. Points to the return expression
+--       of the predicate function. This is the original expression given as
+--       the predicate except that occurrences of the type are replaced by
+--       occurrences of the formal parameter of the predicate function (note
+--       that the spec of this function including this formal parameter name)
+--       is available from the Subprograms_For_Type field (it can be accessed
+--       as Predicate_Function (typ). Also, in the case where a predicate is
+--       inherited, the expression is of the form:
+--
+--         expression AND THEN xxxPredicate (typ2 (ent))
+--
+--       where typ2 is the type from which the predicate is inherited, ent is
+--       the entity for the current predicate function, and xxxPredicate is the
+--       inherited predicate (from typ2). Finally for a predicate that inherits
+--       from another predicate but does not add a predicate of its own, the
+--       expression may consist of the above xxxPredicate call on its own.
+
 --    Status_Flag_Or_Transient_Decl (Node15)
 --       Defined in variables and constants. Applies to objects that require
 --       special treatment by the finalization machinery, such as extended
@@ -5452,6 +5472,7 @@
    --    Scalar_Range                        (Node20)
    --    Delta_Value                         (Ureal18)
    --    Small_Value                         (Ureal21)
+   --    Static_Real_Or_String_Predicate     (Node25)
    --    Has_Machine_Radix_Clause            (Flag83)
    --    Machine_Radix_10                    (Flag84)
    --    Aft_Value                           (synth)
@@ -5557,6 +5578,7 @@
    --    Float_Rep                           (Uint10)   (Float_Rep_Kind)
    --    Default_Aspect_Value                (Node19)   (base type only)
    --    Scalar_Range                        (Node20)
+   --    Static_Real_Or_String_Predicate     (Node25)
    --    Machine_Emax_Value                  (synth)
    --    Machine_Emin_Value                  (synth)
    --    Machine_Mantissa_Value              (synth)
@@ -5777,6 +5799,7 @@
    --    Delta_Value                         (Ureal18)
    --    Default_Aspect_Value                (Node19)   (base type only)
    --    Scalar_Range                        (Node20)
+   --    Static_Real_Or_String_Predicate     (Node25)
    --    Small_Value                         (Ureal21)
    --    Has_Small_Clause                    (Flag67)
    --    Aft_Value                           (synth)
@@ -6048,6 +6071,7 @@
    --  E_String_Subtype
    --    First_Index                         (Node17)
    --    Component_Type                      (Node20)   (base type only)
+   --    Static_Real_Or_String_Predicate     (Node25)
    --    Is_Constrained                      (Flag12)
    --    Next_Index                          (synth)
    --    Number_Dimensions                   (synth)
@@ -6791,6 +6815,7 @@
    function Static_Elaboration_Desired          (Id : E) return B;
    function Static_Initialization               (Id : E) return N;
    function Static_Discrete_Predicate           (Id : E) return S;
+   function Static_Real_Or_String_Predicate     (Id : E) return N;
    function Status_Flag_Or_Transient_Decl       (Id : E) return E;
    function Storage_Size_Variable               (Id : E) return E;
    function Stored_Constraint                   (Id : E) return L;
@@ -7425,6 +7450,7 @@
    procedure Set_Static_Elaboration_Desired      (Id : E; V : B);
    procedure Set_Static_Initialization           (Id : E; V : N);
    procedure Set_Static_Discrete_Predicate       (Id : E; V : S);
+   procedure Set_Static_Real_Or_String_Predicate (Id : E; V : N);
    procedure Set_Status_Flag_Or_Transient_Decl   (Id : E; V : E);
    procedure Set_Storage_Size_Variable           (Id : E; V : E);
    procedure Set_Stored_Constraint               (Id : E; V : L);
@@ -8209,6 +8235,7 @@
    pragma Inline (Static_Elaboration_Desired);
    pragma Inline (Static_Initialization);
    pragma Inline (Static_Discrete_Predicate);
+   pragma Inline (Static_Real_Or_String_Predicate);
    pragma Inline (Status_Flag_Or_Transient_Decl);
    pragma Inline (Storage_Size_Variable);
    pragma Inline (Stored_Constraint);
@@ -8642,6 +8669,7 @@
    pragma Inline (Set_Static_Elaboration_Desired);
    pragma Inline (Set_Static_Initialization);
    pragma Inline (Set_Static_Discrete_Predicate);
+   pragma Inline (Set_Static_Real_Or_String_Predicate);
    pragma Inline (Set_Status_Flag_Or_Transient_Decl);
    pragma Inline (Set_Storage_Size_Variable);
    pragma Inline (Set_Stored_Constraint);
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 213161)
+++ ChangeLog	(revision 213162)
@@ -1,5 +1,18 @@
 2014-07-29  Robert Dewar  <dewar@adacore.com>
 
+	* einfo.ads, einfo.adb (Static_Real_Or_String_Predicate): New function
+	(Set_Static_Real_Or_String_Predicate): New procedure
+	* sem_ch13.adb (Build_Predicate_Functions): Accomodate static
+	string predicates (Is_Predicate_Static): Handle static string
+	predicates.
+	* sem_eval.adb (Real_Or_String_Static_Predicate_Matches):
+	New procedure (Check_Expression_Against_Static_Predicate):
+	Deal with static string predicates, now fully implemented
+	(Eval_Relational_Op): Allow string equality/inequality as static
+	if not comes from source.
+
+2014-07-29  Robert Dewar  <dewar@adacore.com>
+
 	* sem_aggr.adb, exp_ch5.adb, sem_ch5.adb, exp_util.adb, einfo.adb,
 	einfo.ads, sem_util.adb, sem_attr.adb, sem_case.adb, sem_eval.adb,
 	sem_eval.ads, sem_ch13.adb: General cleanup of static predicate
Index: sem_eval.adb
===================================================================
--- sem_eval.adb	(revision 213161)
+++ sem_eval.adb	(revision 213162)
@@ -227,6 +227,16 @@
    --  this is an illegality if N is static, and should generate a warning
    --  otherwise.
 
+   function Real_Or_String_Static_Predicate_Matches
+     (Val : Node_Id;
+      Typ : Entity_Id) return Boolean;
+   --  This is the function used to evaluate real or string static predicates.
+   --  Val is an unanalyzed N_Real_Literal or N_String_Literal node, which
+   --  represents the value to be tested against the predicate. Typ is the
+   --  type with the predicate, from which the predicate expression can be
+   --  extracted. The result returned is True if the given value satisfies
+   --  the predicate.
+
    procedure Rewrite_In_Raise_CE (N : Node_Id; Exp : Node_Id);
    --  N and Exp are nodes representing an expression, Exp is known to raise
    --  CE. N is rewritten in term of Exp in the optimal way.
@@ -339,23 +349,36 @@
       --  an explicitly specified Dynamic_Predicate whose expression met the
       --  rules for being predicate-static).
 
-      --  If we are not generating code, nothing more to do (why???)
+      --  Case of real static predicate
 
-      if Operating_Mode < Generate_Code then
-         return;
-      end if;
+      if Is_Real_Type (Typ) then
+         if Real_Or_String_Static_Predicate_Matches
+              (Val => Make_Real_Literal (Sloc (Expr), Expr_Value_R (Expr)),
+               Typ => Typ)
+         then
+            return;
+         end if;
 
-      --  If we have the real case, then for now, not implemented
+      --  Case of string static predicate
 
-      if not Is_Discrete_Type (Typ) then
-         Error_Msg_N ("??real predicate not applied", Expr);
-         return;
-      end if;
+      elsif Is_String_Type (Typ) then
+         if Real_Or_String_Static_Predicate_Matches
+           (Val => Expr_Value_S (Expr),
+            Typ => Typ)
+         then
+            return;
+         end if;
 
-      --  If static predicate matches, nothing to do
+      --  Case of discrete static predicate
 
-      if Choices_Match (Expr, Static_Discrete_Predicate (Typ)) = Match then
-         return;
+      else
+         pragma Assert (Is_Discrete_Type (Typ));
+
+         --  If static predicate matches, nothing to do
+
+         if Choices_Match (Expr, Static_Discrete_Predicate (Typ)) = Match then
+            return;
+         end if;
       end if;
 
       --  Here we know that the predicate will fail
@@ -3052,6 +3075,10 @@
    --  both operands are static (RM 4.9(7), 4.9(20)), except that for strings,
    --  the result is never static, even if the operands are.
 
+   --  However, for internally generated nodes, we allow string equality and
+   --  inequality to be static. This is because we rewrite A in "ABC" as an
+   --  equality test A = "ABC", and the former is definitely static.
+
    procedure Eval_Relational_Op (N : Node_Id) is
       Left   : constant Node_Id   := Left_Opnd (N);
       Right  : constant Node_Id   := Right_Opnd (N);
@@ -3289,9 +3316,16 @@
 
          --  Only comparisons of scalars can give static results. In
          --  particular, comparisons of strings never yield a static
-         --  result, even if both operands are static strings.
+         --  result, even if both operands are static strings, except that
+         --  as noted above, we allow equality/inequality for strings.
 
-         if not Is_Scalar_Type (Typ) then
+         if Is_String_Type (Typ)
+           and then not Comes_From_Source (N)
+           and then Nkind_In (N, N_Op_Eq, N_Op_Ne)
+         then
+            null;
+
+         elsif not Is_Scalar_Type (Typ) then
             Is_Static_Expression := False;
             Set_Is_Static_Expression (N, False);
          end if;
@@ -3307,9 +3341,8 @@
             Otype := Find_Universal_Operator_Type (N);
          end if;
 
-         --  For static real type expressions, we cannot use
-         --  Compile_Time_Compare since it worries about run-time
-         --  results which are not exact.
+         --  For static real type expressions, do not use Compile_Time_Compare
+         --  since it worries about run-time results which are not exact.
 
          if Is_Static_Expression and then Is_Real_Type (Typ) then
             declare
@@ -5322,6 +5355,112 @@
       end if;
    end Predicates_Match;
 
+   ---------------------------------------------
+   -- Real_Or_String_Static_Predicate_Matches --
+   ---------------------------------------------
+
+   function Real_Or_String_Static_Predicate_Matches
+     (Val : Node_Id;
+      Typ : Entity_Id) return Boolean
+   is
+      Expr : constant Node_Id := Static_Real_Or_String_Predicate (Typ);
+      --  The predicate expression from the type
+
+      Pfun : constant Entity_Id := Predicate_Function (Typ);
+      --  The entity for the predicate function
+
+      Ent_Name : constant Name_Id := Chars (First_Formal (Pfun));
+      --  The name of the formal of the predicate function. Occurrences of the
+      --  type name in Expr have been rewritten as references to this formal,
+      --  and it has a unique name, so we can identify references by this name.
+
+      Copy : Node_Id;
+      --  Copy of the predicate function tree
+
+      function Process (N : Node_Id) return Traverse_Result;
+      --  Function used to process nodes during the traversal in which we will
+      --  find occurrences of the entity name, and replace such occurrences
+      --  by a real literal with the value to be tested.
+
+      procedure Traverse is new Traverse_Proc (Process);
+      --  The actual traversal procedure
+
+      -------------
+      -- Process --
+      -------------
+
+      function Process (N : Node_Id) return Traverse_Result is
+      begin
+         if Nkind (N) = N_Identifier and then Chars (N) = Ent_Name then
+            declare
+               Nod : constant Node_Id := New_Copy (Val);
+            begin
+               Set_Sloc (Nod, Sloc (N));
+               Rewrite (N, Nod);
+               return Skip;
+            end;
+
+         else
+            return OK;
+         end if;
+      end Process;
+
+   --  Start of processing for Real_Or_String_Static_Predicate_Matches
+
+   begin
+      --  First deal with special case of inherited predicate, where the
+      --  predicate expression looks like:
+
+      --     Expr and then xxPredicate (typ (Ent))
+
+      --  where Expr is the predicate expression for this level, and the
+      --  right operand is the call to evaluate the inherited predicate.
+
+      if Nkind (Expr) = N_And_Then
+        and then Nkind (Right_Opnd (Expr)) = N_Function_Call
+      then
+         --  OK we have the inherited case, so make a call to evaluate the
+         --  inherited predicate. If that fails, so do we!
+
+         if not
+           Real_Or_String_Static_Predicate_Matches
+             (Val => Val,
+              Typ => Etype (First_Formal (Entity (Name (Right_Opnd (Expr))))))
+         then
+            return False;
+         end if;
+
+         --  Use the left operand for the continued processing
+
+         Copy := Copy_Separate_Tree (Left_Opnd (Expr));
+
+      --  Case where call to predicate function appears on its own
+
+      elsif Nkind (Expr) =  N_Function_Call then
+
+         --  Here the result is just the result of calling the inner predicate
+
+         return
+           Real_Or_String_Static_Predicate_Matches
+             (Val => Val,
+              Typ => Etype (First_Formal (Entity (Name (Expr)))));
+
+      --  If no inherited predicate, copy whole expression
+
+      else
+         Copy := Copy_Separate_Tree (Expr);
+      end if;
+
+      --  Now we replace occurrences of the entity by the value
+
+      Traverse (Copy);
+
+      --  And analyze the resulting static expression to see if it is True
+
+      Analyze_And_Resolve (Copy, Standard_Boolean);
+      return Is_True (Expr_Value (Copy));
+   end Real_Or_String_Static_Predicate_Matches;
+
    -------------------------
    -- Rewrite_In_Raise_CE --
    -------------------------
Index: sem_ch13.adb
===================================================================
--- sem_ch13.adb	(revision 213161)
+++ sem_ch13.adb	(revision 213162)
@@ -8002,10 +8002,16 @@
          --  yes even if we have an explicit Dynamic_Predicate present.
 
          declare
-            PS : constant Boolean := Is_Predicate_Static (Expr, Object_Name);
+            PS : Boolean;
             EN : Node_Id;
 
          begin
+            if not Is_Scalar_Type (Typ) and then not Is_String_Type (Typ) then
+               PS := False;
+            else
+               PS := Is_Predicate_Static (Expr, Object_Name);
+            end if;
+
             --  Case where we have a predicate-static aspect
 
             if PS then
@@ -8033,6 +8039,11 @@
                   if No (Static_Discrete_Predicate (Typ)) then
                      Set_Has_Static_Predicate (Typ, False);
                   end if;
+
+               --  For real or string subtype, save predicate expression
+
+               elsif Is_Real_Type (Typ) or else Is_String_Type (Typ) then
+                  Set_Static_Real_Or_String_Predicate (Typ, Expr);
                end if;
 
             --  Case of dynamic predicate (expression is not predicate-static)
@@ -8060,14 +8071,13 @@
                --  Now post appropriate message
 
                if Has_Static_Predicate_Aspect (Typ) then
-                  if Is_Scalar_Type (Typ) then
+                  if Is_Scalar_Type (Typ) or else Is_String_Type (Typ) then
                      Error_Msg_F
                        ("expression is not predicate-static (RM 4.3.2(16-22))",
                         EN);
                   else
-                     Error_Msg_FE
-                       ("static predicate not allowed for non-scalar type&",
-                        EN, Typ);
+                     Error_Msg_F
+                       ("static predicate requires scalar or string type", EN);
                   end if;
                end if;
             end if;
@@ -10362,6 +10372,9 @@
    -- Is_Predicate_Static --
    -------------------------
 
+   --  Note: the basic legality of the expression has already been checked, so
+   --  we don't need to worry about cases or ranges on strings for example.
+
    function Is_Predicate_Static
      (Expr : Node_Id;
       Nam  : Name_Id) return Boolean
@@ -10462,12 +10475,6 @@
    --  Start of processing for Is_Predicate_Static
 
    begin
-      --  Only scalar types can be predicate-static
-
-      if not Is_Scalar_Type (Etype (Expr)) then
-         return False;
-      end if;
-
       --  Predicate_Static means one of the following holds. Numbers are the
       --  corresponding paragraph numbers in (RM 3.2.4(16-22)).
 
@@ -10502,7 +10509,20 @@
       --  operand is the current instance, and the other is a static
       --  expression.
 
+      --  Note: the RM is clearly wrong here in not excluding string types.
+      --  Without this exclusion, we would allow expressions like X > "ABC"
+      --  to be considered as predicate-static, which is clearly not intended,
+      --  since the idea is for predicate-static to be a subset of normal
+      --  static expressions (and "DEF" > "ABC" is not a static expression).
+
+      --  However, we do allow internally generated (not from source) equality
+      --  and inequality operations to be valid on strings (this helps deal
+      --  with cases where we transform A in "ABC" to A = "ABC).
+
       elsif Nkind (Expr) in N_Op_Compare
+        and then ((not Is_String_Type (Etype (Left_Opnd (Expr))))
+                    or else (Nkind_In (Expr, N_Op_Eq, N_Op_Ne)
+                              and then not Comes_From_Source (Expr)))
         and then ((Is_Type_Ref (Left_Opnd (Expr))
                     and then Is_OK_Static_Expression (Right_Opnd (Expr)))
                   or else


More information about the Gcc-patches mailing list