[PATCH 3/4] gdb: split get_discrete_bounds in two

Simon Marchi simon.marchi@efficios.com
Mon Nov 23 16:21:19 GMT 2020


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/gdbtypes.c | 187 ++++++++++++++++++++++++++++++++++---------------
 1 file changed, 130 insertions(+), 57 deletions(-)

diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c
index b47bd28945d..4df23cfe0fe 100644
--- a/gdb/gdbtypes.c
+++ b/gdb/gdbtypes.c
@@ -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
-- 
2.29.2



More information about the Gdb-patches mailing list