gdb
[deliverable/binutils-gdb.git] / gdb / valops.c
index 1667368d5025571d7a9ff51b40d5ef4f84566f60..ca3408345b61f681a2e37ec970862eb1f7445932 100644 (file)
@@ -527,6 +527,258 @@ value_cast (struct type *type, struct value *arg2)
     }
 }
 
+/* The C++ reinterpret_cast operator.  */
+
+struct value *
+value_reinterpret_cast (struct type *type, struct value *arg)
+{
+  struct value *result;
+  struct type *real_type = check_typedef (type);
+  struct type *arg_type, *dest_type;
+  int is_ref = 0;
+  enum type_code dest_code, arg_code;
+
+  /* Do reference, function, and array conversion.  */
+  arg = coerce_array (arg);
+
+  /* Attempt to preserve the type the user asked for.  */
+  dest_type = type;
+
+  /* If we are casting to a reference type, transform
+     reinterpret_cast<T&>(V) to *reinterpret_cast<T*>(&V).  */
+  if (TYPE_CODE (real_type) == TYPE_CODE_REF)
+    {
+      is_ref = 1;
+      arg = value_addr (arg);
+      dest_type = lookup_pointer_type (TYPE_TARGET_TYPE (dest_type));
+      real_type = lookup_pointer_type (real_type);
+    }
+
+  arg_type = value_type (arg);
+
+  dest_code = TYPE_CODE (real_type);
+  arg_code = TYPE_CODE (arg_type);
+
+  /* We can convert pointer types, or any pointer type to int, or int
+     type to pointer.  */
+  if ((dest_code == TYPE_CODE_PTR && arg_code == TYPE_CODE_INT)
+      || (dest_code == TYPE_CODE_INT && arg_code == TYPE_CODE_PTR)
+      || (dest_code == TYPE_CODE_METHODPTR && arg_code == TYPE_CODE_INT)
+      || (dest_code == TYPE_CODE_INT && arg_code == TYPE_CODE_METHODPTR)
+      || (dest_code == TYPE_CODE_MEMBERPTR && arg_code == TYPE_CODE_INT)
+      || (dest_code == TYPE_CODE_INT && arg_code == TYPE_CODE_MEMBERPTR)
+      || (dest_code == arg_code
+         && (dest_code == TYPE_CODE_PTR
+             || dest_code == TYPE_CODE_METHODPTR
+             || dest_code == TYPE_CODE_MEMBERPTR)))
+    result = value_cast (dest_type, arg);
+  else
+    error (_("Invalid reinterpret_cast"));
+
+  if (is_ref)
+    result = value_cast (type, value_ref (value_ind (result)));
+
+  return result;
+}
+
+/* A helper for value_dynamic_cast.  This implements the first of two
+   runtime checks: we iterate over all the base classes of the value's
+   class which are equal to the desired class; if only one of these
+   holds the value, then it is the answer.  */
+
+static int
+dynamic_cast_check_1 (struct type *desired_type,
+                     const bfd_byte *contents,
+                     CORE_ADDR address,
+                     struct type *search_type,
+                     CORE_ADDR arg_addr,
+                     struct type *arg_type,
+                     struct value **result)
+{
+  int i, result_count = 0;
+
+  for (i = 0; i < TYPE_N_BASECLASSES (search_type) && result_count < 2; ++i)
+    {
+      int offset = baseclass_offset (search_type, i, contents, address);
+      if (offset == -1)
+       error (_("virtual baseclass botch"));
+      if (class_types_same_p (desired_type, TYPE_BASECLASS (search_type, i)))
+       {
+         if (address + offset >= arg_addr
+             && address + offset < arg_addr + TYPE_LENGTH (arg_type))
+           {
+             ++result_count;
+             if (!*result)
+               *result = value_at_lazy (TYPE_BASECLASS (search_type, i),
+                                        address + offset);
+           }
+       }
+      else
+       result_count += dynamic_cast_check_1 (desired_type,
+                                             contents + offset,
+                                             address + offset,
+                                             TYPE_BASECLASS (search_type, i),
+                                             arg_addr,
+                                             arg_type,
+                                             result);
+    }
+
+  return result_count;
+}
+
+/* A helper for value_dynamic_cast.  This implements the second of two
+   runtime checks: we look for a unique public sibling class of the
+   argument's declared class.  */
+
+static int
+dynamic_cast_check_2 (struct type *desired_type,
+                     const bfd_byte *contents,
+                     CORE_ADDR address,
+                     struct type *search_type,
+                     struct value **result)
+{
+  int i, result_count = 0;
+
+  for (i = 0; i < TYPE_N_BASECLASSES (search_type) && result_count < 2; ++i)
+    {
+      int offset;
+
+      if (! BASETYPE_VIA_PUBLIC (search_type, i))
+       continue;
+
+      offset = baseclass_offset (search_type, i, contents, address);
+      if (offset == -1)
+       error (_("virtual baseclass botch"));
+      if (class_types_same_p (desired_type, TYPE_BASECLASS (search_type, i)))
+       {
+         ++result_count;
+         if (*result == NULL)
+           *result = value_at_lazy (TYPE_BASECLASS (search_type, i),
+                                    address + offset);
+       }
+      else
+       result_count += dynamic_cast_check_2 (desired_type,
+                                             contents + offset,
+                                             address + offset,
+                                             TYPE_BASECLASS (search_type, i),
+                                             result);
+    }
+
+  return result_count;
+}
+
+/* The C++ dynamic_cast operator.  */
+
+struct value *
+value_dynamic_cast (struct type *type, struct value *arg)
+{
+  int unambiguous = 0, full, top, using_enc;
+  struct type *resolved_type = check_typedef (type);
+  struct type *arg_type = check_typedef (value_type (arg));
+  struct type *class_type, *rtti_type;
+  struct value *result, *tem, *original_arg = arg;
+  CORE_ADDR addr;
+  int is_ref = TYPE_CODE (resolved_type) == TYPE_CODE_REF;
+
+  if (TYPE_CODE (resolved_type) != TYPE_CODE_PTR
+      && TYPE_CODE (resolved_type) != TYPE_CODE_REF)
+    error (_("Argument to dynamic_cast must be a pointer or reference type"));
+  if (TYPE_CODE (TYPE_TARGET_TYPE (resolved_type)) != TYPE_CODE_VOID
+      && TYPE_CODE (TYPE_TARGET_TYPE (resolved_type)) != TYPE_CODE_CLASS)
+    error (_("Argument to dynamic_cast must be pointer to class or `void *'"));
+
+  class_type = check_typedef (TYPE_TARGET_TYPE (resolved_type));
+  if (TYPE_CODE (resolved_type) == TYPE_CODE_PTR)
+    {
+      if (TYPE_CODE (arg_type) != TYPE_CODE_PTR
+         && ! (TYPE_CODE (arg_type) == TYPE_CODE_INT
+               && value_as_long (arg) == 0))
+       error (_("Argument to dynamic_cast does not have pointer type"));
+      if (TYPE_CODE (arg_type) == TYPE_CODE_PTR)
+       {
+         arg_type = check_typedef (TYPE_TARGET_TYPE (arg_type));
+         if (TYPE_CODE (arg_type) != TYPE_CODE_CLASS)
+           error (_("Argument to dynamic_cast does not have pointer to class type"));
+       }
+
+      /* Handle NULL pointers.  */
+      if (value_as_long (arg) == 0)
+       return value_zero (type, not_lval);
+
+      arg = value_ind (arg);
+    }
+  else
+    {
+      if (TYPE_CODE (arg_type) != TYPE_CODE_CLASS)
+       error (_("Argument to dynamic_cast does not have class type"));
+    }
+
+  /* If the classes are the same, just return the argument.  */
+  if (class_types_same_p (class_type, arg_type))
+    return value_cast (type, arg);
+
+  /* If the target type is a unique base class of the argument's
+     declared type, just cast it.  */
+  if (is_ancestor (class_type, arg_type))
+    {
+      if (is_unique_ancestor (class_type, arg))
+       return value_cast (type, original_arg);
+      error (_("Ambiguous dynamic_cast"));
+    }
+
+  rtti_type = value_rtti_type (arg, &full, &top, &using_enc);
+  if (! rtti_type)
+    error (_("Couldn't determine value's most derived type for dynamic_cast"));
+
+  /* Compute the most derived object's address.  */
+  addr = value_address (arg);
+  if (full)
+    {
+      /* Done.  */
+    }
+  else if (using_enc)
+    addr += top;
+  else
+    addr += top + value_embedded_offset (arg);
+
+  /* dynamic_cast<void *> means to return a pointer to the
+     most-derived object.  */
+  if (TYPE_CODE (resolved_type) == TYPE_CODE_PTR
+      && TYPE_CODE (TYPE_TARGET_TYPE (resolved_type)) == TYPE_CODE_VOID)
+    return value_at_lazy (type, addr);
+
+  tem = value_at (type, addr);
+
+  /* The first dynamic check specified in 5.2.7.  */
+  if (is_public_ancestor (arg_type, TYPE_TARGET_TYPE (resolved_type)))
+    {
+      if (class_types_same_p (rtti_type, TYPE_TARGET_TYPE (resolved_type)))
+       return tem;
+      result = NULL;
+      if (dynamic_cast_check_1 (TYPE_TARGET_TYPE (resolved_type),
+                               value_contents (tem), value_address (tem),
+                               rtti_type, addr,
+                               arg_type,
+                               &result) == 1)
+       return value_cast (type,
+                          is_ref ? value_ref (result) : value_addr (result));
+    }
+
+  /* The second dynamic check specified in 5.2.7.  */
+  result = NULL;
+  if (is_public_ancestor (arg_type, rtti_type)
+      && dynamic_cast_check_2 (TYPE_TARGET_TYPE (resolved_type),
+                              value_contents (tem), value_address (tem),
+                              rtti_type, &result) == 1)
+    return value_cast (type,
+                      is_ref ? value_ref (result) : value_addr (result));
+
+  if (TYPE_CODE (resolved_type) == TYPE_CODE_PTR)
+    return value_zero (type, not_lval);
+
+  error (_("dynamic_cast failed"));
+}
+
 /* Create a value of type TYPE that is zero, and return it.  */
 
 struct value *
This page took 0.026544 seconds and 4 git commands to generate.