diff options
Diffstat (limited to 'Objects/methodobject.c')
| -rw-r--r-- | Objects/methodobject.c | 107 | 
1 files changed, 57 insertions, 50 deletions
| diff --git a/Objects/methodobject.c b/Objects/methodobject.c index f2616d4ef0..b5467a4687 100644 --- a/Objects/methodobject.c +++ b/Objects/methodobject.c @@ -37,6 +37,7 @@ PyCFunction_NewEx(PyMethodDef *ml, PyObject *self, PyObject *module)          if (op == NULL)              return NULL;      } +    op->m_weakreflist = NULL;      op->m_ml = ml;      Py_XINCREF(self);      op->m_self = self; @@ -77,68 +78,71 @@ PyCFunction_GetFlags(PyObject *op)  }  PyObject * -PyCFunction_Call(PyObject *func, PyObject *arg, PyObject *kw) +PyCFunction_Call(PyObject *func, PyObject *args, PyObject *kwds)  { -#define CHECK_RESULT(res) assert(res != NULL || PyErr_Occurred()) -      PyCFunctionObject* f = (PyCFunctionObject*)func;      PyCFunction meth = PyCFunction_GET_FUNCTION(func);      PyObject *self = PyCFunction_GET_SELF(func); -    PyObject *res; +    PyObject *arg, *res;      Py_ssize_t size; +    int flags; -    switch (PyCFunction_GET_FLAGS(func) & ~(METH_CLASS | METH_STATIC | METH_COEXIST)) { -    case METH_VARARGS: -        if (kw == NULL || PyDict_Size(kw) == 0) { -            res = (*meth)(self, arg); -            CHECK_RESULT(res); -            return res; -        } -        break; -    case METH_VARARGS | METH_KEYWORDS: -        res = (*(PyCFunctionWithKeywords)meth)(self, arg, kw); -        CHECK_RESULT(res); -        return res; -    case METH_NOARGS: -        if (kw == NULL || PyDict_Size(kw) == 0) { -            size = PyTuple_GET_SIZE(arg); -            if (size == 0) { -                res = (*meth)(self, NULL); -                CHECK_RESULT(res); -                return res; -            } -            PyErr_Format(PyExc_TypeError, -                "%.200s() takes no arguments (%zd given)", -                f->m_ml->ml_name, size); +    /* PyCFunction_Call() must not be called with an exception set, +       because it may clear it (directly or indirectly) and so the +       caller looses its exception */ +    assert(!PyErr_Occurred()); + +    flags = PyCFunction_GET_FLAGS(func) & ~(METH_CLASS | METH_STATIC | METH_COEXIST); + +    if (flags == (METH_VARARGS | METH_KEYWORDS)) { +        res = (*(PyCFunctionWithKeywords)meth)(self, args, kwds); +    } +    else { +        if (kwds != NULL && PyDict_Size(kwds) != 0) { +            PyErr_Format(PyExc_TypeError, "%.200s() takes no keyword arguments", +                         f->m_ml->ml_name);              return NULL;          } -        break; -    case METH_O: -        if (kw == NULL || PyDict_Size(kw) == 0) { -            size = PyTuple_GET_SIZE(arg); -            if (size == 1) { -                res = (*meth)(self, PyTuple_GET_ITEM(arg, 0)); -                CHECK_RESULT(res); -                return res; + +        switch (flags) { +        case METH_VARARGS: +            res = (*meth)(self, args); +            break; + +        case METH_NOARGS: +            size = PyTuple_GET_SIZE(args); +            if (size != 0) { +                PyErr_Format(PyExc_TypeError, +                    "%.200s() takes no arguments (%zd given)", +                    f->m_ml->ml_name, size); +                return NULL;              } -            PyErr_Format(PyExc_TypeError, -                "%.200s() takes exactly one argument (%zd given)", -                f->m_ml->ml_name, size); + +            res = (*meth)(self, NULL); +            break; + +        case METH_O: +            size = PyTuple_GET_SIZE(args); +            if (size != 1) { +                PyErr_Format(PyExc_TypeError, +                    "%.200s() takes exactly one argument (%zd given)", +                    f->m_ml->ml_name, size); +                return NULL; +            } + +            arg = PyTuple_GET_ITEM(args, 0); +            res = (*meth)(self, arg); +            break; + +        default: +            PyErr_SetString(PyExc_SystemError, +                            "Bad call flags in PyCFunction_Call. " +                            "METH_OLDARGS is no longer supported!");              return NULL;          } -        break; -    default: -        PyErr_SetString(PyExc_SystemError, "Bad call flags in " -                        "PyCFunction_Call. METH_OLDARGS is no " -                        "longer supported!"); - -        return NULL;      } -    PyErr_Format(PyExc_TypeError, "%.200s() takes no keyword arguments", -                 f->m_ml->ml_name); -    return NULL; -#undef CHECK_RESULT +    return _Py_CheckFunctionResult(func, res, NULL);  }  /* Methods (the standard built-in methods, that is) */ @@ -147,6 +151,9 @@ static void  meth_dealloc(PyCFunctionObject *m)  {      _PyObject_GC_UNTRACK(m); +    if (m->m_weakreflist != NULL) { +        PyObject_ClearWeakRefs((PyObject*) m); +    }      Py_XDECREF(m->m_self);      Py_XDECREF(m->m_module);      if (numfree < PyCFunction_MAXFREELIST) { @@ -352,7 +359,7 @@ PyTypeObject PyCFunction_Type = {      (traverseproc)meth_traverse,                /* tp_traverse */      0,                                          /* tp_clear */      meth_richcompare,                           /* tp_richcompare */ -    0,                                          /* tp_weaklistoffset */ +    offsetof(PyCFunctionObject, m_weakreflist), /* tp_weaklistoffset */      0,                                          /* tp_iter */      0,                                          /* tp_iternext */      meth_methods,                               /* tp_methods */ | 
