gdb: split get_discrete_bounds in two
authorSimon Marchi <simon.marchi@efficios.com>
Wed, 9 Dec 2020 18:52:03 +0000 (13:52 -0500)
committerSimon Marchi <simon.marchi@polymtl.ca>
Wed, 9 Dec 2020 18:52:03 +0000 (13:52 -0500)
get_discrete_bounds is not flexible for ranges (TYPE_CODE_RANGE), in the
sense that it returns true (success) only if both bounds are present and
constant values.

This is a problem for code that only needs to know the low bound and
fails unnecessarily if the high bound is unknown.

Split the function in two, get_discrete_low_bound and
get_discrete_high_bound, that both return an optional.  Provide a new
implementation of get_discrete_bounds based on the two others, so the
callers don't have to be changed.

gdb/ChangeLog:

* gdbtypes.c (get_discrete_bounds): Implement with
get_discrete_low_bound and get_discrete_high_bound.
(get_discrete_low_bound): New.
(get_discrete_high_bound): New.

Change-Id: I986b5e9c0dd969800e3fb9546af9c827d52e80d0

gdb/ChangeLog
gdb/gdbtypes.c

index e7f083ca58f5c8a4ec43ea469e60cf08a6f8d8bc..3b022c1813fef8d425292d7e13aa25c4fc833716 100644 (file)
@@ -1,3 +1,10 @@
+2020-12-09  Simon Marchi  <simon.marchi@efficios.com>
+
+       * gdbtypes.c (get_discrete_bounds): Implement with
+       get_discrete_low_bound and get_discrete_high_bound.
+       (get_discrete_low_bound): New.
+       (get_discrete_high_bound): New.
+
 2020-12-09  Simon Marchi  <simon.marchi@efficios.com>
 
        * gdbtypes.h (get_discrete_bounds): Return bool, adjust all
index f1b19b58aab4f805067f80417b8190e2d677f2cc..367ca5f311c8319dd69577452358eaf74f39550e 100644 (file)
@@ -1036,71 +1036,127 @@ has_static_range (const struct range_bounds *bounds)
          && bounds->stride.kind () == PROP_CONST);
 }
 
-/* See gdbtypes.h.  */
+/* If TYPE's low bound is a known constant, return it, else return nullopt.  */
 
-bool
-get_discrete_bounds (struct type *type, LONGEST *lowp, LONGEST *highp)
+static gdb::optional<LONGEST>
+get_discrete_low_bound (struct type *type)
 {
   type = check_typedef (type);
   switch (type->code ())
     {
     case TYPE_CODE_RANGE:
-      /* This function currently only works for ranges with two defined,
-        constant bounds.  */
-      if (type->bounds ()->low.kind () != PROP_CONST
-         || type->bounds ()->high.kind () != PROP_CONST)
+      {
+       /* This function only works for ranges with a constant low bound.  */
+       if (type->bounds ()->low.kind () != PROP_CONST)
+         return {};
+
+       LONGEST low = type->bounds ()->low.const_val ();
+
+       if (TYPE_TARGET_TYPE (type)->code () == TYPE_CODE_ENUM)
+         {
+           gdb::optional<LONGEST> low_pos
+             = discrete_position (TYPE_TARGET_TYPE (type), low);
+
+           if (low_pos.has_value ())
+             low = *low_pos;
+         }
+
+       return low;
+      }
+
+    case TYPE_CODE_ENUM:
+      {
+       if (type->num_fields () > 0)
+         {
+           /* The enums may not be sorted by value, so search all
+              entries.  */
+           LONGEST low = TYPE_FIELD_ENUMVAL (type, 0);
+
+           for (int i = 0; i < type->num_fields (); i++)
+             {
+               if (TYPE_FIELD_ENUMVAL (type, i) < low)
+                 low = TYPE_FIELD_ENUMVAL (type, i);
+             }
+
+           /* Set unsigned indicator if warranted.  */
+           if (low >= 0)
+             type->set_is_unsigned (true);
+
+           return low;
+         }
+       else
+         return 0;
+      }
+
+    case TYPE_CODE_BOOL:
+      return 0;
+
+    case TYPE_CODE_INT:
+      if (TYPE_LENGTH (type) > sizeof (LONGEST))       /* Too big */
        return false;
 
-      *lowp = type->bounds ()->low.const_val ();
-      *highp = type->bounds ()->high.const_val ();
+      if (!type->is_unsigned ())
+       return -(1 << (TYPE_LENGTH (type) * TARGET_CHAR_BIT - 1));
 
-      if (TYPE_TARGET_TYPE (type)->code () == TYPE_CODE_ENUM)
-       {
-         gdb::optional<LONGEST> low_pos
-           = discrete_position (TYPE_TARGET_TYPE (type), *lowp);
+      /* fall through */
+    case TYPE_CODE_CHAR:
+      return 0;
 
-         if (low_pos.has_value ())
-           *lowp = *low_pos;
+    default:
+      return false;
+    }
+}
 
-         gdb::optional<LONGEST> high_pos
-           = discrete_position (TYPE_TARGET_TYPE (type), *highp);
+/* If TYPE's high bound is a known constant, return it, else return nullopt.  */
 
-         if (high_pos.has_value ())
-           *highp = *high_pos;
-       }
-      return true;
+static gdb::optional<LONGEST>
+get_discrete_high_bound (struct type *type)
+{
+  type = check_typedef (type);
+  switch (type->code ())
+    {
+    case TYPE_CODE_RANGE:
+      {
+       /* This function only works for ranges with a constant high bound.  */
+       if (type->bounds ()->high.kind () != PROP_CONST)
+         return {};
+
+       LONGEST high = type->bounds ()->high.const_val ();
+
+       if (TYPE_TARGET_TYPE (type)->code () == TYPE_CODE_ENUM)
+         {
+           gdb::optional<LONGEST> high_pos
+             = discrete_position (TYPE_TARGET_TYPE (type), high);
+
+           if (high_pos.has_value ())
+             high = *high_pos;
+         }
+
+       return high;
+      }
 
     case TYPE_CODE_ENUM:
-      if (type->num_fields () > 0)
-       {
-         /* The enums may not be sorted by value, so search all
-            entries.  */
-         int i;
+      {
+       if (type->num_fields () > 0)
+         {
+           /* The enums may not be sorted by value, so search all
+              entries.  */
+           LONGEST high = TYPE_FIELD_ENUMVAL (type, 0);
 
-         *lowp = *highp = TYPE_FIELD_ENUMVAL (type, 0);
-         for (i = 0; i < type->num_fields (); i++)
-           {
-             if (TYPE_FIELD_ENUMVAL (type, i) < *lowp)
-               *lowp = TYPE_FIELD_ENUMVAL (type, i);
-             if (TYPE_FIELD_ENUMVAL (type, i) > *highp)
-               *highp = TYPE_FIELD_ENUMVAL (type, i);
-           }
+           for (int i = 0; i < type->num_fields (); i++)
+             {
+               if (TYPE_FIELD_ENUMVAL (type, i) > high)
+                 high = TYPE_FIELD_ENUMVAL (type, i);
+             }
 
-         /* Set unsigned indicator if warranted.  */
-         if (*lowp >= 0)
-           type->set_is_unsigned (true);
-       }
-      else
-       {
-         *lowp = 0;
-         *highp = -1;
-       }
-      return true;
+           return high;
+         }
+       else
+         return -1;
+      }
 
     case TYPE_CODE_BOOL:
-      *lowp = 0;
-      *highp = 1;
-      return true;
+      return 1;
 
     case TYPE_CODE_INT:
       if (TYPE_LENGTH (type) > sizeof (LONGEST))       /* Too big */
@@ -1108,25 +1164,42 @@ get_discrete_bounds (struct type *type, LONGEST *lowp, LONGEST *highp)
 
       if (!type->is_unsigned ())
        {
-         *lowp = -(1 << (TYPE_LENGTH (type) * TARGET_CHAR_BIT - 1));
-         *highp = -*lowp - 1;
-         return true;
+         LONGEST low = -(1 << (TYPE_LENGTH (type) * TARGET_CHAR_BIT - 1));
+         return -low - 1;
        }
+
       /* fall through */
     case TYPE_CODE_CHAR:
-      *lowp = 0;
-      /* This round-about calculation is to avoid shifting by
-        TYPE_LENGTH (type) * TARGET_CHAR_BIT, which will not work
-        if TYPE_LENGTH (type) == sizeof (LONGEST).  */
-      *highp = 1 << (TYPE_LENGTH (type) * TARGET_CHAR_BIT - 1);
-      *highp = (*highp - 1) | *highp;
-      return true;
+      {
+       /* This round-about calculation is to avoid shifting by
+          TYPE_LENGTH (type) * TARGET_CHAR_BIT, which will not work
+          if TYPE_LENGTH (type) == sizeof (LONGEST).  */
+       LONGEST high = 1 << (TYPE_LENGTH (type) * TARGET_CHAR_BIT - 1);
+       return (high - 1) | high;
+      }
 
     default:
       return false;
     }
 }
 
+/* See gdbtypes.h.  */
+
+bool
+get_discrete_bounds (struct type *type, LONGEST *lowp, LONGEST *highp)
+{
+  gdb::optional<LONGEST> low = get_discrete_low_bound (type);
+  gdb::optional<LONGEST> high = get_discrete_high_bound (type);
+
+  if (!low.has_value () || !high.has_value ())
+    return false;
+
+  *lowp = *low;
+  *highp = *high;
+
+  return true;
+}
+
 /* See gdbtypes.h  */
 
 bool