PR c++/12266
[deliverable/binutils-gdb.git] / gdb / python / py-type.c
index ea6c8e53cb454c27615466f4d88b9f4a7e4461a9..335342e4871bd3946128060f71c54ebb063bde10 100644 (file)
@@ -1,6 +1,6 @@
 /* Python interface to types.
 
-   Copyright (C) 2008, 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
@@ -27,6 +27,8 @@
 #include "demangle.h"
 #include "objfiles.h"
 #include "language.h"
+#include "vec.h"
+#include "bcache.h"
 
 typedef struct pyty_type_object
 {
@@ -216,6 +218,13 @@ typy_fields (PyObject *self, PyObject *args)
   PyObject *result;
   int i;
   struct type *type = ((type_object *) self)->type;
+  volatile struct gdb_exception except;
+
+  TRY_CATCH (except, RETURN_MASK_ALL)
+    {
+      CHECK_TYPEDEF (type);
+    }
+  GDB_PY_HANDLE_EXCEPTION (except);
 
   /* We would like to make a tuple here, make fields immutable, and
      then memoize the result (and perhaps make Field.type() lazy).
@@ -267,13 +276,13 @@ typy_strip_typedefs (PyObject *self, PyObject *args)
 static PyObject *
 typy_array (PyObject *self, PyObject *args)
 {
-  int n1, n2;
+  long n1, n2;
   PyObject *n2_obj = NULL;
   struct type *array = NULL;
   struct type *type = ((type_object *) self)->type;
   volatile struct gdb_exception except;
 
-  if (! PyArg_ParseTuple (args, "i|O", &n1, &n2_obj))
+  if (! PyArg_ParseTuple (args, "l|O", &n1, &n2_obj))
     return NULL;
 
   if (n2_obj)
@@ -284,8 +293,8 @@ typy_array (PyObject *self, PyObject *args)
                           _("Array bound must be an integer"));
          return NULL;
        }
-      n2 = (int) PyInt_AsLong (n2_obj);
-      if (PyErr_Occurred ())
+
+      if (! gdb_py_int_as_long (n2_obj, &n2))
        return NULL;
     }
   else
@@ -488,7 +497,7 @@ typy_get_sizeof (PyObject *self, void *closure)
 }
 
 static struct type *
-typy_lookup_typename (char *type_name, struct block *block)
+typy_lookup_typename (const char *type_name, struct block *block)
 {
   struct type *type = NULL;
   volatile struct gdb_exception except;
@@ -568,8 +577,10 @@ typy_legacy_template_argument (struct type *type, struct block *block,
 {
   int i;
   struct demangle_component *demangled;
+  struct demangle_parse_info *info;
   const char *err;
   struct type *argtype;
+  struct cleanup *cleanup;
 
   if (TYPE_NAME (type) == NULL)
     {
@@ -578,12 +589,14 @@ typy_legacy_template_argument (struct type *type, struct block *block,
     }
 
   /* Note -- this is not thread-safe.  */
-  demangled = cp_demangled_name_to_comp (TYPE_NAME (type), &err);
-  if (! demangled)
+  info = cp_demangled_name_to_comp (TYPE_NAME (type), &err);
+  if (! info)
     {
       PyErr_SetString (PyExc_RuntimeError, err);
       return NULL;
     }
+  demangled = info->tree;
+  cleanup = make_cleanup_cp_demangled_name_parse_free (info);
 
   /* Strip off component names.  */
   while (demangled->type == DEMANGLE_COMPONENT_QUAL_NAME
@@ -592,6 +605,7 @@ typy_legacy_template_argument (struct type *type, struct block *block,
 
   if (demangled->type != DEMANGLE_COMPONENT_TEMPLATE)
     {
+      do_cleanups (cleanup);
       PyErr_SetString (PyExc_RuntimeError, _("Type is not a template."));
       return NULL;
     }
@@ -604,12 +618,14 @@ typy_legacy_template_argument (struct type *type, struct block *block,
 
   if (! demangled)
     {
+      do_cleanups (cleanup);
       PyErr_Format (PyExc_RuntimeError, _("No argument %d in template."),
                    argno);
       return NULL;
     }
 
   argtype = typy_lookup_type (demangled->u.s_binary.left, block);
+  do_cleanups (cleanup);
   if (! argtype)
     return NULL;
 
@@ -641,9 +657,13 @@ typy_template_argument (PyObject *self, PyObject *args)
        }
     }
 
-  type = check_typedef (type);
-  if (TYPE_CODE (type) == TYPE_CODE_REF)
-    type = check_typedef (TYPE_TARGET_TYPE (type));
+  TRY_CATCH (except, RETURN_MASK_ALL)
+    {
+      type = check_typedef (type);
+      if (TYPE_CODE (type) == TYPE_CODE_REF)
+       type = check_typedef (TYPE_TARGET_TYPE (type));
+    }
+  GDB_PY_HANDLE_EXCEPTION (except);
 
   /* We might not have DW_TAG_template_*, so try to parse the type's
      name.  This is inefficient if we do not have a template type --
@@ -710,6 +730,200 @@ typy_str (PyObject *self)
   return result;
 }
 
+/* An entry in the type-equality bcache.  */
+
+typedef struct type_equality_entry
+{
+  struct type *type1, *type2;
+} type_equality_entry_d;
+
+DEF_VEC_O (type_equality_entry_d);
+
+/* A helper function to compare two strings.  Returns 1 if they are
+   the same, 0 otherwise.  Handles NULLs properly.  */
+
+static int
+compare_strings (const char *s, const char *t)
+{
+  if (s == NULL && t != NULL)
+    return 0;
+  else if (s != NULL && t == NULL)
+    return 0;
+  else if (s == NULL && t== NULL)
+    return 1;
+  return strcmp (s, t) == 0;
+}
+
+/* A helper function for typy_richcompare that checks two types for
+   "deep" equality.  Returns Py_EQ if the types are considered the
+   same, Py_NE otherwise.  */
+
+static int
+check_types_equal (struct type *type1, struct type *type2,
+                  VEC (type_equality_entry_d) **worklist)
+{
+  CHECK_TYPEDEF (type1);
+  CHECK_TYPEDEF (type2);
+
+  if (type1 == type2)
+    return Py_EQ;
+
+  if (TYPE_CODE (type1) != TYPE_CODE (type2)
+      || TYPE_LENGTH (type1) != TYPE_LENGTH (type2)
+      || TYPE_UNSIGNED (type1) != TYPE_UNSIGNED (type2)
+      || TYPE_NOSIGN (type1) != TYPE_NOSIGN (type2)
+      || TYPE_VARARGS (type1) != TYPE_VARARGS (type2)
+      || TYPE_VECTOR (type1) != TYPE_VECTOR (type2)
+      || TYPE_NOTTEXT (type1) != TYPE_NOTTEXT (type2)
+      || TYPE_INSTANCE_FLAGS (type1) != TYPE_INSTANCE_FLAGS (type2)
+      || TYPE_NFIELDS (type1) != TYPE_NFIELDS (type2))
+    return Py_NE;
+
+  if (!compare_strings (TYPE_TAG_NAME (type1), TYPE_TAG_NAME (type2)))
+    return Py_NE;
+  if (!compare_strings (TYPE_NAME (type1), TYPE_NAME (type2)))
+    return Py_NE;
+
+  if (TYPE_CODE (type1) == TYPE_CODE_RANGE)
+    {
+      if (memcmp (TYPE_RANGE_DATA (type1), TYPE_RANGE_DATA (type2),
+                 sizeof (*TYPE_RANGE_DATA (type1))) != 0)
+       return Py_NE;
+    }
+  else
+    {
+      int i;
+
+      for (i = 0; i < TYPE_NFIELDS (type1); ++i)
+       {
+         const struct field *field1 = &TYPE_FIELD (type1, i);
+         const struct field *field2 = &TYPE_FIELD (type2, i);
+         struct type_equality_entry entry;
+
+         if (FIELD_ARTIFICIAL (*field1) != FIELD_ARTIFICIAL (*field2)
+             || FIELD_BITSIZE (*field1) != FIELD_BITSIZE (*field2)
+             || FIELD_LOC_KIND (*field1) != FIELD_LOC_KIND (*field2))
+           return Py_NE;
+         if (!compare_strings (FIELD_NAME (*field1), FIELD_NAME (*field2)))
+           return Py_NE;
+         switch (FIELD_LOC_KIND (*field1))
+           {
+           case FIELD_LOC_KIND_BITPOS:
+             if (FIELD_BITPOS (*field1) != FIELD_BITPOS (*field2))
+               return Py_NE;
+             break;
+           case FIELD_LOC_KIND_PHYSADDR:
+             if (FIELD_STATIC_PHYSADDR (*field1)
+                 != FIELD_STATIC_PHYSADDR (*field2))
+               return Py_NE;
+             break;
+           case FIELD_LOC_KIND_PHYSNAME:
+             if (!compare_strings (FIELD_STATIC_PHYSNAME (*field1),
+                                   FIELD_STATIC_PHYSNAME (*field2)))
+               return Py_NE;
+             break;
+           }
+
+         entry.type1 = FIELD_TYPE (*field1);
+         entry.type2 = FIELD_TYPE (*field2);
+         VEC_safe_push (type_equality_entry_d, *worklist, &entry);
+       }
+    }
+
+  if (TYPE_TARGET_TYPE (type1) != NULL)
+    {
+      struct type_equality_entry entry;
+      int added;
+
+      if (TYPE_TARGET_TYPE (type2) == NULL)
+       return Py_NE;
+
+      entry.type1 = TYPE_TARGET_TYPE (type1);
+      entry.type2 = TYPE_TARGET_TYPE (type2);
+      VEC_safe_push (type_equality_entry_d, *worklist, &entry);
+    }
+  else if (TYPE_TARGET_TYPE (type2) != NULL)
+    return Py_NE;
+
+  return Py_EQ;
+}
+
+/* Check types on a worklist for equality.  Returns Py_NE if any pair
+   is not equal, Py_EQ if they are all considered equal.  */
+
+static int
+check_types_worklist (VEC (type_equality_entry_d) **worklist,
+                     struct bcache *cache)
+{
+  while (!VEC_empty (type_equality_entry_d, *worklist))
+    {
+      struct type_equality_entry entry;
+      int added;
+
+      entry = *VEC_last (type_equality_entry_d, *worklist);
+      VEC_pop (type_equality_entry_d, *worklist);
+
+      /* If the type pair has already been visited, we know it is
+        ok.  */
+      bcache_full (&entry, sizeof (entry), cache, &added);
+      if (!added)
+       continue;
+
+      if (check_types_equal (entry.type1, entry.type2, worklist) == Py_NE)
+       return Py_NE;
+    }
+
+  return Py_EQ;
+}
+
+/* Implement the richcompare method.  */
+
+static PyObject *
+typy_richcompare (PyObject *self, PyObject *other, int op)
+{
+  int result = Py_NE;
+  struct type *type1 = type_object_to_type (self);
+  struct type *type2 = type_object_to_type (other);
+  volatile struct gdb_exception except;
+
+  /* We can only compare ourselves to another Type object, and only
+     for equality or inequality.  */
+  if (type2 == NULL || (op != Py_EQ && op != Py_NE))
+    {
+      Py_INCREF (Py_NotImplemented);
+      return Py_NotImplemented;
+    }
+
+  if (type1 == type2)
+    result = Py_EQ;
+  else
+    {
+      struct bcache *cache;
+      VEC (type_equality_entry_d) *worklist = NULL;
+      struct type_equality_entry entry;
+
+      cache = bcache_xmalloc (NULL, NULL);
+
+      entry.type1 = type1;
+      entry.type2 = type2;
+      VEC_safe_push (type_equality_entry_d, worklist, &entry);
+
+      TRY_CATCH (except, RETURN_MASK_ALL)
+       {
+         result = check_types_worklist (&worklist, cache);
+       }
+      if (except.reason < 0)
+       result = Py_NE;
+
+      bcache_xfree (cache);
+      VEC_free (type_equality_entry_d, worklist);
+    }
+
+  if (op == result)
+    Py_RETURN_TRUE;
+  Py_RETURN_FALSE;
+}
+
 \f
 
 static const struct objfile_data *typy_objfile_data_key;
@@ -813,7 +1027,7 @@ PyObject *
 gdbpy_lookup_type (PyObject *self, PyObject *args, PyObject *kw)
 {
   static char *keywords[] = { "name", "block", NULL };
-  char *type_name = NULL;
+  const char *type_name = NULL;
   struct type *type = NULL;
   PyObject *block_obj = NULL;
   struct block *block = NULL;
@@ -947,7 +1161,7 @@ static PyTypeObject type_object_type =
   "GDB type object",             /* tp_doc */
   0,                             /* tp_traverse */
   0,                             /* tp_clear */
-  0,                             /* tp_richcompare */
+  typy_richcompare,              /* tp_richcompare */
   0,                             /* tp_weaklistoffset */
   0,                             /* tp_iter */
   0,                             /* tp_iternext */
This page took 0.032419 seconds and 4 git commands to generate.