Introduce array_operation
authorTom Tromey <tom@tromey.com>
Mon, 8 Mar 2021 14:27:57 +0000 (07:27 -0700)
committerTom Tromey <tom@tromey.com>
Mon, 8 Mar 2021 14:28:29 +0000 (07:28 -0700)
This adds class array_operation, which implements OP_ARRAY.

gdb/ChangeLog
2021-03-08  Tom Tromey  <tom@tromey.com>

* expop.h (class array_operation): New.
* eval.c (array_operation::evaluate_struct_tuple)
(array_operation::evaluate): New methods.

gdb/ChangeLog
gdb/eval.c
gdb/expop.h

index 627969aea63a84434636712285fbdf83653541e6..03a7ff1fab27bdfbd82b8162699d21c4c8c8b223 100644 (file)
@@ -1,3 +1,9 @@
+2021-03-08  Tom Tromey  <tom@tromey.com>
+
+       * expop.h (class array_operation): New.
+       * eval.c (array_operation::evaluate_struct_tuple)
+       (array_operation::evaluate): New methods.
+
 2021-03-08  Tom Tromey  <tom@tromey.com>
 
        * expop.h (class adl_func_operation): New.
index 972e63035b383e8a50f6efa958d410d9341d56cf..812068465d7be1da44aa74d597945944558dcb6a 100644 (file)
@@ -2572,6 +2572,206 @@ adl_func_operation::evaluate (struct type *expect_type,
 
 }
 
+/* This function evaluates brace-initializers (in C/C++) for
+   structure types.  */
+
+struct value *
+array_operation::evaluate_struct_tuple (struct value *struct_val,
+                                       struct expression *exp,
+                                       enum noside noside, int nargs)
+{
+  const std::vector<operation_up> &in_args = std::get<2> (m_storage);
+  struct type *struct_type = check_typedef (value_type (struct_val));
+  struct type *field_type;
+  int fieldno = -1;
+
+  int idx = 0;
+  while (--nargs >= 0)
+    {
+      struct value *val = NULL;
+      int bitpos, bitsize;
+      bfd_byte *addr;
+
+      fieldno++;
+      /* Skip static fields.  */
+      while (fieldno < struct_type->num_fields ()
+            && field_is_static (&struct_type->field (fieldno)))
+       fieldno++;
+      if (fieldno >= struct_type->num_fields ())
+       error (_("too many initializers"));
+      field_type = struct_type->field (fieldno).type ();
+      if (field_type->code () == TYPE_CODE_UNION
+         && TYPE_FIELD_NAME (struct_type, fieldno)[0] == '0')
+       error (_("don't know which variant you want to set"));
+
+      /* Here, struct_type is the type of the inner struct,
+        while substruct_type is the type of the inner struct.
+        These are the same for normal structures, but a variant struct
+        contains anonymous union fields that contain substruct fields.
+        The value fieldno is the index of the top-level (normal or
+        anonymous union) field in struct_field, while the value
+        subfieldno is the index of the actual real (named inner) field
+        in substruct_type.  */
+
+      field_type = struct_type->field (fieldno).type ();
+      if (val == 0)
+       val = in_args[idx++]->evaluate (field_type, exp, noside);
+
+      /* Now actually set the field in struct_val.  */
+
+      /* Assign val to field fieldno.  */
+      if (value_type (val) != field_type)
+       val = value_cast (field_type, val);
+
+      bitsize = TYPE_FIELD_BITSIZE (struct_type, fieldno);
+      bitpos = TYPE_FIELD_BITPOS (struct_type, fieldno);
+      addr = value_contents_writeable (struct_val) + bitpos / 8;
+      if (bitsize)
+       modify_field (struct_type, addr,
+                     value_as_long (val), bitpos % 8, bitsize);
+      else
+       memcpy (addr, value_contents (val),
+               TYPE_LENGTH (value_type (val)));
+
+    }
+  return struct_val;
+}
+
+value *
+array_operation::evaluate (struct type *expect_type,
+                          struct expression *exp,
+                          enum noside noside)
+{
+  int tem;
+  int tem2 = std::get<0> (m_storage);
+  int tem3 = std::get<1> (m_storage);
+  const std::vector<operation_up> &in_args = std::get<2> (m_storage);
+  int nargs = tem3 - tem2 + 1;
+  struct type *type = expect_type ? check_typedef (expect_type) : nullptr;
+
+  if (expect_type != nullptr && noside != EVAL_SKIP
+      && type->code () == TYPE_CODE_STRUCT)
+    {
+      struct value *rec = allocate_value (expect_type);
+
+      memset (value_contents_raw (rec), '\0', TYPE_LENGTH (type));
+      return evaluate_struct_tuple (rec, exp, noside, nargs);
+    }
+
+  if (expect_type != nullptr && noside != EVAL_SKIP
+      && type->code () == TYPE_CODE_ARRAY)
+    {
+      struct type *range_type = type->index_type ();
+      struct type *element_type = TYPE_TARGET_TYPE (type);
+      struct value *array = allocate_value (expect_type);
+      int element_size = TYPE_LENGTH (check_typedef (element_type));
+      LONGEST low_bound, high_bound, index;
+
+      if (!get_discrete_bounds (range_type, &low_bound, &high_bound))
+       {
+         low_bound = 0;
+         high_bound = (TYPE_LENGTH (type) / element_size) - 1;
+       }
+      index = low_bound;
+      memset (value_contents_raw (array), 0, TYPE_LENGTH (expect_type));
+      for (tem = nargs; --nargs >= 0;)
+       {
+         struct value *element;
+
+         element = in_args[index - low_bound]->evaluate (element_type,
+                                                         exp, noside);
+         if (value_type (element) != element_type)
+           element = value_cast (element_type, element);
+         if (index > high_bound)
+           /* To avoid memory corruption.  */
+           error (_("Too many array elements"));
+         memcpy (value_contents_raw (array)
+                 + (index - low_bound) * element_size,
+                 value_contents (element),
+                 element_size);
+         index++;
+       }
+      return array;
+    }
+
+  if (expect_type != nullptr && noside != EVAL_SKIP
+      && type->code () == TYPE_CODE_SET)
+    {
+      struct value *set = allocate_value (expect_type);
+      gdb_byte *valaddr = value_contents_raw (set);
+      struct type *element_type = type->index_type ();
+      struct type *check_type = element_type;
+      LONGEST low_bound, high_bound;
+
+      /* Get targettype of elementtype.  */
+      while (check_type->code () == TYPE_CODE_RANGE
+            || check_type->code () == TYPE_CODE_TYPEDEF)
+       check_type = TYPE_TARGET_TYPE (check_type);
+
+      if (!get_discrete_bounds (element_type, &low_bound, &high_bound))
+       error (_("(power)set type with unknown size"));
+      memset (valaddr, '\0', TYPE_LENGTH (type));
+      int idx = 0;
+      for (tem = 0; tem < nargs; tem++)
+       {
+         LONGEST range_low, range_high;
+         struct type *range_low_type, *range_high_type;
+         struct value *elem_val;
+
+         elem_val = in_args[idx++]->evaluate (element_type, exp, noside);
+         range_low_type = range_high_type = value_type (elem_val);
+         range_low = range_high = value_as_long (elem_val);
+
+         /* Check types of elements to avoid mixture of elements from
+            different types. Also check if type of element is "compatible"
+            with element type of powerset.  */
+         if (range_low_type->code () == TYPE_CODE_RANGE)
+           range_low_type = TYPE_TARGET_TYPE (range_low_type);
+         if (range_high_type->code () == TYPE_CODE_RANGE)
+           range_high_type = TYPE_TARGET_TYPE (range_high_type);
+         if ((range_low_type->code () != range_high_type->code ())
+             || (range_low_type->code () == TYPE_CODE_ENUM
+                 && (range_low_type != range_high_type)))
+           /* different element modes.  */
+           error (_("POWERSET tuple elements of different mode"));
+         if ((check_type->code () != range_low_type->code ())
+             || (check_type->code () == TYPE_CODE_ENUM
+                 && range_low_type != check_type))
+           error (_("incompatible POWERSET tuple elements"));
+         if (range_low > range_high)
+           {
+             warning (_("empty POWERSET tuple range"));
+             continue;
+           }
+         if (range_low < low_bound || range_high > high_bound)
+           error (_("POWERSET tuple element out of range"));
+         range_low -= low_bound;
+         range_high -= low_bound;
+         for (; range_low <= range_high; range_low++)
+           {
+             int bit_index = (unsigned) range_low % TARGET_CHAR_BIT;
+
+             if (gdbarch_byte_order (exp->gdbarch) == BFD_ENDIAN_BIG)
+               bit_index = TARGET_CHAR_BIT - 1 - bit_index;
+             valaddr[(unsigned) range_low / TARGET_CHAR_BIT]
+               |= 1 << bit_index;
+           }
+       }
+      return set;
+    }
+
+  value **argvec = XALLOCAVEC (struct value *, nargs);
+  for (tem = 0; tem < nargs; tem++)
+    {
+      /* Ensure that array expressions are coerced into pointer
+        objects.  */
+      argvec[tem] = in_args[tem]->evaluate_with_coercion (exp, noside);
+    }
+  if (noside == EVAL_SKIP)
+    return eval_skip_value (exp);
+  return value_array (tem2, tem3, argvec);
+}
+
 }
 
 struct value *
index 0785df939e4798c1695b06089afabc76aaf27384..9b5c4ea35e44b6f771a4385bba03c15f72685d20 100644 (file)
@@ -2049,6 +2049,28 @@ public:
   { return OP_ADL_FUNC; }
 };
 
+/* The OP_ARRAY operation.  */
+class array_operation
+  : public tuple_holding_operation<int, int, std::vector<operation_up>>
+{
+public:
+
+  using tuple_holding_operation::tuple_holding_operation;
+
+  value *evaluate (struct type *expect_type,
+                  struct expression *exp,
+                  enum noside noside) override;
+
+  enum exp_opcode opcode () const override
+  { return OP_ARRAY; }
+
+private:
+
+  struct value *evaluate_struct_tuple (struct value *struct_val,
+                                      struct expression *exp,
+                                      enum noside noside, int nargs);
+};
+
 } /* namespace expr */
 
 #endif /* EXPOP_H */