From c637bce20aaaf836ab2cfbb123b9472e5ad0ab47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Wed, 19 Feb 2025 12:18:37 +0100 Subject: [PATCH] gh-111178: fix UBSan failures in `Modules/_datetimemodule.c` (GH-129774) Add cast macros for date and time objects Fix UBSan failures for `PyDateTime_Delta`, `PyDateTime_Date`, `PyDateTime_TZInfo`, `PyDateTime_TimeZone`, `PyDateTime_Time`, `PyDateTime_DateTime`, `PyDateTime_IsoCalendarDate` Fix up naming --- Modules/_datetimemodule.c | 560 +++++++++++++++++++++----------------- 1 file changed, 313 insertions(+), 247 deletions(-) diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index b5ccf2f7b65d63..07d7089be09d20 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -58,7 +58,13 @@ typedef struct { * the per-module objects stored in module state. The macros for the * static objects don't need to be passed a state, but the consistency * of doing so is more clear. We use a dedicated noop macro, NO_STATE, - * to make the special case obvious. */ + * to make the special case obvious. + * + * The casting macros perform a simple fast pointer cast without + * checking the runtime type. In the future, we may decide whether + * to include that check and whether to provide a fast pointer cast + * macro for pointers known to be of correct time. + */ #define NO_STATE NULL @@ -70,23 +76,31 @@ typedef struct { #define TIMEZONE_TYPE(st) &PyDateTime_TimeZoneType #define ISOCALENDAR_DATE_TYPE(st) st->isocalendar_date_type +#define PyDate_CAST(op) ((PyDateTime_Date *)(op)) #define PyDate_Check(op) PyObject_TypeCheck(op, DATE_TYPE(NO_STATE)) #define PyDate_CheckExact(op) Py_IS_TYPE(op, DATE_TYPE(NO_STATE)) +#define PyDateTime_CAST(op) ((PyDateTime_DateTime *)(op)) #define PyDateTime_Check(op) PyObject_TypeCheck(op, DATETIME_TYPE(NO_STATE)) #define PyDateTime_CheckExact(op) Py_IS_TYPE(op, DATETIME_TYPE(NO_STATE)) +#define PyTime_CAST(op) ((PyDateTime_Time *)(op)) #define PyTime_Check(op) PyObject_TypeCheck(op, TIME_TYPE(NO_STATE)) #define PyTime_CheckExact(op) Py_IS_TYPE(op, TIME_TYPE(NO_STATE)) +#define PyDelta_CAST(op) ((PyDateTime_Delta *)(op)) #define PyDelta_Check(op) PyObject_TypeCheck(op, DELTA_TYPE(NO_STATE)) #define PyDelta_CheckExact(op) Py_IS_TYPE(op, DELTA_TYPE(NO_STATE)) +#define PyTZInfo_CAST(op) ((PyDateTime_TZInfo *)(op)) #define PyTZInfo_Check(op) PyObject_TypeCheck(op, TZINFO_TYPE(NO_STATE)) #define PyTZInfo_CheckExact(op) Py_IS_TYPE(op, TZINFO_TYPE(NO_STATE)) +#define PyTimeZone_CAST(op) ((PyDateTime_TimeZone *)(op)) #define PyTimezone_Check(op) PyObject_TypeCheck(op, TIMEZONE_TYPE(NO_STATE)) +#define PyIsoCalendarDate_CAST(op) ((PyDateTime_IsoCalendarDate *)(op)) + #define CONST_US_PER_MS(st) st->us_per_ms #define CONST_US_PER_SECOND(st) st->us_per_second #define CONST_US_PER_MINUTE(st) st->us_per_minute @@ -295,9 +309,9 @@ clear_current_module(PyInterpreterState *interp, PyObject *expected) #define TIME_SET_FOLD(o, v) (PyDateTime_TIME_GET_FOLD(o) = (v)) /* Delta accessors for timedelta. */ -#define GET_TD_DAYS(o) (((PyDateTime_Delta *)(o))->days) -#define GET_TD_SECONDS(o) (((PyDateTime_Delta *)(o))->seconds) -#define GET_TD_MICROSECONDS(o) (((PyDateTime_Delta *)(o))->microseconds) +#define GET_TD_DAYS(o) (PyDelta_CAST(o)->days) +#define GET_TD_SECONDS(o) (PyDelta_CAST(o)->seconds) +#define GET_TD_MICROSECONDS(o) (PyDelta_CAST(o)->microseconds) #define SET_TD_DAYS(o, v) ((o)->days = (v)) #define SET_TD_SECONDS(o, v) ((o)->seconds = (v)) @@ -1418,7 +1432,7 @@ create_timezone(PyObject *offset, PyObject *name) return (PyObject *)self; } -static int delta_bool(PyDateTime_Delta *self); +static int delta_bool(PyObject *op); static PyDateTime_TimeZone utc_timezone; static PyObject * @@ -1428,7 +1442,7 @@ new_timezone(PyObject *offset, PyObject *name) assert(PyDelta_Check(offset)); assert(name == NULL || PyUnicode_Check(name)); - if (name == NULL && delta_bool((PyDateTime_Delta *)offset) == 0) { + if (name == NULL && delta_bool(offset) == 0) { return Py_NewRef(CONST_UTC(NO_STATE)); } if ((GET_TD_DAYS(offset) == -1 && @@ -1663,7 +1677,7 @@ tzinfo_from_isoformat_results(int rv, int tzoffset, int tz_useconds) */ static PyObject * -format_ctime(PyDateTime_Date *date, int hours, int minutes, int seconds) +format_ctime(PyObject *date, int hours, int minutes, int seconds) { static const char * const DayNames[] = { "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun" @@ -1681,7 +1695,7 @@ format_ctime(PyDateTime_Date *date, int hours, int minutes, int seconds) GET_YEAR(date)); } -static PyObject *delta_negative(PyDateTime_Delta *self); +static PyObject *delta_negative(PyObject *op); /* Add formatted UTC offset string to buf. buf has no more than * buflen bytes remaining. The UTC offset is gotten by calling @@ -1714,7 +1728,7 @@ format_utcoffset(char *buf, size_t buflen, const char *sep, /* Offset is normalized, so it is negative if days < 0 */ if (GET_TD_DAYS(offset) < 0) { sign = '-'; - Py_SETREF(offset, delta_negative((PyDateTime_Delta *)offset)); + Py_SETREF(offset, delta_negative(offset)); if (offset == NULL) return -1; } @@ -2416,7 +2430,7 @@ delta_add(PyObject *left, PyObject *right) } static PyObject * -delta_negative(PyDateTime_Delta *self) +delta_negative(PyObject *self) { return new_delta(-GET_TD_DAYS(self), -GET_TD_SECONDS(self), @@ -2425,7 +2439,7 @@ delta_negative(PyDateTime_Delta *self) } static PyObject * -delta_positive(PyDateTime_Delta *self) +delta_positive(PyObject *self) { /* Could optimize this (by returning self) if this isn't a * subclass -- but who uses unary + ? Approximately nobody. @@ -2437,7 +2451,7 @@ delta_positive(PyDateTime_Delta *self) } static PyObject * -delta_abs(PyDateTime_Delta *self) +delta_abs(PyObject *self) { PyObject *result; @@ -2502,8 +2516,9 @@ delta_richcompare(PyObject *self, PyObject *other, int op) static PyObject *delta_getstate(PyDateTime_Delta *self); static Py_hash_t -delta_hash(PyDateTime_Delta *self) +delta_hash(PyObject *op) { + PyDateTime_Delta *self = PyDelta_CAST(op); if (self->hashcode == -1) { PyObject *temp = delta_getstate(self); if (temp != NULL) { @@ -2867,7 +2882,7 @@ delta_new(PyTypeObject *type, PyObject *args, PyObject *kw) } static int -delta_bool(PyDateTime_Delta *self) +delta_bool(PyObject *self) { return (GET_TD_DAYS(self) != 0 || GET_TD_SECONDS(self) != 0 @@ -2875,7 +2890,7 @@ delta_bool(PyDateTime_Delta *self) } static PyObject * -delta_repr(PyDateTime_Delta *self) +delta_repr(PyObject *self) { PyObject *args = Py_GetConstant(Py_CONSTANT_EMPTY_STR); @@ -2924,7 +2939,7 @@ delta_repr(PyDateTime_Delta *self) } static PyObject * -delta_str(PyDateTime_Delta *self) +delta_str(PyObject *self) { int us = GET_TD_MICROSECONDS(self); int seconds = GET_TD_SECONDS(self); @@ -2964,12 +2979,12 @@ delta_getstate(PyDateTime_Delta *self) } static PyObject * -delta_total_seconds(PyObject *self, PyObject *Py_UNUSED(ignored)) +delta_total_seconds(PyObject *op, PyObject *Py_UNUSED(dummy)) { PyObject *total_seconds; PyObject *total_microseconds; - total_microseconds = delta_to_microseconds((PyDateTime_Delta *)self); + total_microseconds = delta_to_microseconds(PyDelta_CAST(op)); if (total_microseconds == NULL) return NULL; @@ -2984,8 +2999,9 @@ delta_total_seconds(PyObject *self, PyObject *Py_UNUSED(ignored)) } static PyObject * -delta_reduce(PyDateTime_Delta* self, PyObject *Py_UNUSED(ignored)) +delta_reduce(PyObject *op, PyObject *Py_UNUSED(dummy)) { + PyDateTime_Delta *self = PyDelta_CAST(op); return Py_BuildValue("ON", Py_TYPE(self), delta_getstate(self)); } @@ -3008,7 +3024,7 @@ static PyMethodDef delta_methods[] = { {"total_seconds", delta_total_seconds, METH_NOARGS, PyDoc_STR("Total seconds in the duration.")}, - {"__reduce__", (PyCFunction)delta_reduce, METH_NOARGS, + {"__reduce__", delta_reduce, METH_NOARGS, PyDoc_STR("__reduce__() -> (cls, state)")}, {NULL, NULL}, @@ -3028,10 +3044,10 @@ static PyNumberMethods delta_as_number = { delta_remainder, /* nb_remainder */ delta_divmod, /* nb_divmod */ 0, /* nb_power */ - (unaryfunc)delta_negative, /* nb_negative */ - (unaryfunc)delta_positive, /* nb_positive */ - (unaryfunc)delta_abs, /* nb_absolute */ - (inquiry)delta_bool, /* nb_bool */ + delta_negative, /* nb_negative */ + delta_positive, /* nb_positive */ + delta_abs, /* nb_absolute */ + delta_bool, /* nb_bool */ 0, /*nb_invert*/ 0, /*nb_lshift*/ 0, /*nb_rshift*/ @@ -3067,13 +3083,13 @@ static PyTypeObject PyDateTime_DeltaType = { 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_as_async */ - (reprfunc)delta_repr, /* tp_repr */ + delta_repr, /* tp_repr */ &delta_as_number, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ - (hashfunc)delta_hash, /* tp_hash */ + delta_hash, /* tp_hash */ 0, /* tp_call */ - (reprfunc)delta_str, /* tp_str */ + delta_str, /* tp_str */ PyObject_GenericGetAttr, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ @@ -3125,27 +3141,30 @@ look_up_delta(int days, int seconds, int microseconds, PyTypeObject *type) /* Accessor properties. */ static PyObject * -date_year(PyDateTime_Date *self, void *unused) +date_year(PyObject *op, void *Py_UNUSED(closure)) { + PyDateTime_Date *self = PyDate_CAST(op); return PyLong_FromLong(GET_YEAR(self)); } static PyObject * -date_month(PyDateTime_Date *self, void *unused) +date_month(PyObject *op, void *Py_UNUSED(closure)) { + PyDateTime_Date *self = PyDate_CAST(op); return PyLong_FromLong(GET_MONTH(self)); } static PyObject * -date_day(PyDateTime_Date *self, void *unused) +date_day(PyObject *op, void *Py_UNUSED(closure)) { + PyDateTime_Date *self = PyDate_CAST(op); return PyLong_FromLong(GET_DAY(self)); } static PyGetSetDef date_getset[] = { - {"year", (getter)date_year}, - {"month", (getter)date_month}, - {"day", (getter)date_day}, + {"year", date_year}, + {"month", date_month}, + {"day", date_day}, {NULL} }; @@ -3238,7 +3257,7 @@ date_fromtimestamp(PyObject *cls, PyObject *obj) * generally the same as calling C's time. */ static PyObject * -date_today(PyObject *cls, PyObject *dummy) +date_today(PyObject *cls, PyObject *Py_UNUSED(dummy)) { PyObject *time; PyObject *result; @@ -3505,36 +3524,38 @@ date_subtract(PyObject *left, PyObject *right) /* Various ways to turn a date into a string. */ static PyObject * -date_repr(PyDateTime_Date *self) +date_repr(PyObject *op) { + PyDateTime_Date *self = PyDate_CAST(op); return PyUnicode_FromFormat("%s(%d, %d, %d)", Py_TYPE(self)->tp_name, GET_YEAR(self), GET_MONTH(self), GET_DAY(self)); } static PyObject * -date_isoformat(PyDateTime_Date *self, PyObject *Py_UNUSED(ignored)) +date_isoformat(PyObject *op, PyObject *Py_UNUSED(dummy)) { + PyDateTime_Date *self = PyDate_CAST(op); return PyUnicode_FromFormat("%04d-%02d-%02d", GET_YEAR(self), GET_MONTH(self), GET_DAY(self)); } /* str() calls the appropriate isoformat() method. */ static PyObject * -date_str(PyDateTime_Date *self) +date_str(PyObject *self) { - return PyObject_CallMethodNoArgs((PyObject *)self, &_Py_ID(isoformat)); + return PyObject_CallMethodNoArgs(self, &_Py_ID(isoformat)); } static PyObject * -date_ctime(PyDateTime_Date *self, PyObject *Py_UNUSED(ignored)) +date_ctime(PyObject *self, PyObject *Py_UNUSED(dummy)) { return format_ctime(self, 0, 0, 0); } static PyObject * -date_strftime(PyDateTime_Date *self, PyObject *args, PyObject *kw) +date_strftime(PyObject *self, PyObject *args, PyObject *kw) { /* This method can be inherited, and needs to call the * timetuple() method appropriate to self's class. @@ -3544,21 +3565,20 @@ date_strftime(PyDateTime_Date *self, PyObject *args, PyObject *kw) PyObject *format; static char *keywords[] = {"format", NULL}; - if (! PyArg_ParseTupleAndKeywords(args, kw, "U:strftime", keywords, - &format)) + if (!PyArg_ParseTupleAndKeywords(args, kw, "U:strftime", keywords, + &format)) return NULL; - tuple = PyObject_CallMethodNoArgs((PyObject *)self, &_Py_ID(timetuple)); + tuple = PyObject_CallMethodNoArgs(self, &_Py_ID(timetuple)); if (tuple == NULL) return NULL; - result = wrap_strftime((PyObject *)self, format, tuple, - (PyObject *)self); + result = wrap_strftime(self, format, tuple, self); Py_DECREF(tuple); return result; } static PyObject * -date_format(PyDateTime_Date *self, PyObject *args) +date_format(PyObject *self, PyObject *args) { PyObject *format; @@ -3567,16 +3587,15 @@ date_format(PyDateTime_Date *self, PyObject *args) /* if the format is zero length, return str(self) */ if (PyUnicode_GetLength(format) == 0) - return PyObject_Str((PyObject *)self); + return PyObject_Str(self); - return PyObject_CallMethodOneArg((PyObject *)self, &_Py_ID(strftime), - format); + return PyObject_CallMethodOneArg(self, &_Py_ID(strftime), format); } /* ISO methods. */ static PyObject * -date_isoweekday(PyDateTime_Date *self, PyObject *Py_UNUSED(ignored)) +date_isoweekday(PyObject *self, PyObject *Py_UNUSED(dummy)) { int dow = weekday(GET_YEAR(self), GET_MONTH(self), GET_DAY(self)); @@ -3594,17 +3613,17 @@ typedef struct { } PyDateTime_IsoCalendarDate; static PyObject * -iso_calendar_date_repr(PyDateTime_IsoCalendarDate *self) +iso_calendar_date_repr(PyObject *self) { - PyObject* year = PyTuple_GetItem((PyObject *)self, 0); + PyObject *year = PyTuple_GetItem(self, 0); if (year == NULL) { return NULL; } - PyObject* week = PyTuple_GetItem((PyObject *)self, 1); + PyObject *week = PyTuple_GetItem(self, 1); if (week == NULL) { return NULL; } - PyObject* weekday = PyTuple_GetItem((PyObject *)self, 2); + PyObject *weekday = PyTuple_GetItem(self, 2); if (weekday == NULL) { return NULL; } @@ -3617,7 +3636,7 @@ static PyObject * iso_calendar_date_reduce(PyObject *self, PyObject *Py_UNUSED(ignored)) { // Construct the tuple that this reduces to - PyObject * reduce_tuple = Py_BuildValue( + PyObject *reduce_tuple = Py_BuildValue( "O((OOO))", &PyTuple_Type, PyTuple_GET_ITEM(self, 0), PyTuple_GET_ITEM(self, 1), @@ -3628,9 +3647,9 @@ iso_calendar_date_reduce(PyObject *self, PyObject *Py_UNUSED(ignored)) } static PyObject * -iso_calendar_date_year(PyDateTime_IsoCalendarDate *self, void *unused) +iso_calendar_date_year(PyObject *self, void *Py_UNUSED(closure)) { - PyObject *year = PyTuple_GetItem((PyObject *)self, 0); + PyObject *year = PyTuple_GetItem(self, 0); if (year == NULL) { return NULL; } @@ -3638,9 +3657,9 @@ iso_calendar_date_year(PyDateTime_IsoCalendarDate *self, void *unused) } static PyObject * -iso_calendar_date_week(PyDateTime_IsoCalendarDate *self, void *unused) +iso_calendar_date_week(PyObject *self, void *Py_UNUSED(closure)) { - PyObject *week = PyTuple_GetItem((PyObject *)self, 1); + PyObject *week = PyTuple_GetItem(self, 1); if (week == NULL) { return NULL; } @@ -3648,9 +3667,9 @@ iso_calendar_date_week(PyDateTime_IsoCalendarDate *self, void *unused) } static PyObject * -iso_calendar_date_weekday(PyDateTime_IsoCalendarDate *self, void *unused) +iso_calendar_date_weekday(PyObject *self, void *Py_UNUSED(closure)) { - PyObject *weekday = PyTuple_GetItem((PyObject *)self, 2); + PyObject *weekday = PyTuple_GetItem(self, 2); if (weekday == NULL) { return NULL; } @@ -3658,31 +3677,30 @@ iso_calendar_date_weekday(PyDateTime_IsoCalendarDate *self, void *unused) } static PyGetSetDef iso_calendar_date_getset[] = { - {"year", (getter)iso_calendar_date_year}, - {"week", (getter)iso_calendar_date_week}, - {"weekday", (getter)iso_calendar_date_weekday}, + {"year", iso_calendar_date_year}, + {"week", iso_calendar_date_week}, + {"weekday", iso_calendar_date_weekday}, {NULL} }; static PyMethodDef iso_calendar_date_methods[] = { - {"__reduce__", (PyCFunction)iso_calendar_date_reduce, METH_NOARGS, + {"__reduce__", iso_calendar_date_reduce, METH_NOARGS, PyDoc_STR("__reduce__() -> (cls, state)")}, {NULL, NULL}, }; static int -iso_calendar_date_traverse(PyDateTime_IsoCalendarDate *self, visitproc visit, - void *arg) +iso_calendar_date_traverse(PyObject *self, visitproc visit, void *arg) { Py_VISIT(Py_TYPE(self)); - return PyTuple_Type.tp_traverse((PyObject *)self, visit, arg); + return PyTuple_Type.tp_traverse(self, visit, arg); } static void -iso_calendar_date_dealloc(PyDateTime_IsoCalendarDate *self) +iso_calendar_date_dealloc(PyObject *self) { PyTypeObject *tp = Py_TYPE(self); - PyTuple_Type.tp_dealloc((PyObject *)self); // delegate GC-untrack as well + PyTuple_Type.tp_dealloc(self); // delegate GC-untrack as well Py_DECREF(tp); } @@ -3734,7 +3752,7 @@ iso_calendar_date_new_impl(PyTypeObject *type, int year, int week, } static PyObject * -date_isocalendar(PyDateTime_Date *self, PyObject *Py_UNUSED(ignored)) +date_isocalendar(PyObject *self, PyObject *Py_UNUSED(dummy)) { int year = GET_YEAR(self); int week1_monday = iso_week1_monday(year); @@ -3789,7 +3807,7 @@ date_richcompare(PyObject *self, PyObject *other, int op) } static PyObject * -date_timetuple(PyDateTime_Date *self, PyObject *Py_UNUSED(ignored)) +date_timetuple(PyObject *self, PyObject *Py_UNUSED(dummy)) { return build_struct_time(GET_YEAR(self), GET_MONTH(self), @@ -3825,8 +3843,9 @@ generic_hash(unsigned char *data, int len) static PyObject *date_getstate(PyDateTime_Date *self); static Py_hash_t -date_hash(PyDateTime_Date *self) +date_hash(PyObject *op) { + PyDateTime_Date *self = PyDate_CAST(op); if (self->hashcode == -1) { self->hashcode = generic_hash( (unsigned char *)self->data, _PyDateTime_DATE_DATASIZE); @@ -3836,17 +3855,16 @@ date_hash(PyDateTime_Date *self) } static PyObject * -date_toordinal(PyDateTime_Date *self, PyObject *Py_UNUSED(ignored)) +date_toordinal(PyObject *self, PyObject *Py_UNUSED(dummy)) { return PyLong_FromLong(ymd_to_ord(GET_YEAR(self), GET_MONTH(self), - GET_DAY(self))); + GET_DAY(self))); } static PyObject * -date_weekday(PyDateTime_Date *self, PyObject *Py_UNUSED(ignored)) +date_weekday(PyObject *self, PyObject *Py_UNUSED(dummy)) { int dow = weekday(GET_YEAR(self), GET_MONTH(self), GET_DAY(self)); - return PyLong_FromLong(dow); } @@ -3863,8 +3881,9 @@ date_getstate(PyDateTime_Date *self) } static PyObject * -date_reduce(PyDateTime_Date *self, PyObject *arg) +date_reduce(PyObject *op, PyObject *Py_UNUSED(dummy)) { + PyDateTime_Date *self = PyDate_CAST(op); return Py_BuildValue("(ON)", Py_TYPE(self), date_getstate(self)); } @@ -3873,13 +3892,11 @@ static PyMethodDef date_methods[] = { /* Class methods: */ DATETIME_DATE_FROMTIMESTAMP_METHODDEF - {"fromordinal", (PyCFunction)date_fromordinal, METH_VARARGS | - METH_CLASS, + {"fromordinal", date_fromordinal, METH_VARARGS | METH_CLASS, PyDoc_STR("int -> date corresponding to a proleptic Gregorian " "ordinal.")}, - {"fromisoformat", (PyCFunction)date_fromisoformat, METH_O | - METH_CLASS, + {"fromisoformat", date_fromisoformat, METH_O | METH_CLASS, PyDoc_STR("str -> Construct a date from a string in ISO 8601 format.")}, {"fromisocalendar", _PyCFunction_CAST(date_fromisocalendar), @@ -3888,45 +3905,44 @@ static PyMethodDef date_methods[] = { "number and weekday.\n\n" "This is the inverse of the date.isocalendar() function")}, - {"strptime", (PyCFunction)date_strptime, - METH_VARARGS | METH_CLASS, + {"strptime", date_strptime, METH_VARARGS | METH_CLASS, PyDoc_STR("string, format -> new date parsed from a string " "(like time.strptime()).")}, - {"today", (PyCFunction)date_today, METH_NOARGS | METH_CLASS, + {"today", date_today, METH_NOARGS | METH_CLASS, PyDoc_STR("Current date or datetime: same as " "self.__class__.fromtimestamp(time.time()).")}, /* Instance methods: */ - {"ctime", (PyCFunction)date_ctime, METH_NOARGS, + {"ctime", date_ctime, METH_NOARGS, PyDoc_STR("Return ctime() style string.")}, - {"strftime", _PyCFunction_CAST(date_strftime), METH_VARARGS | METH_KEYWORDS, + {"strftime", _PyCFunction_CAST(date_strftime), METH_VARARGS | METH_KEYWORDS, PyDoc_STR("format -> strftime() style string.")}, - {"__format__", (PyCFunction)date_format, METH_VARARGS, + {"__format__", date_format, METH_VARARGS, PyDoc_STR("Formats self with strftime.")}, - {"timetuple", (PyCFunction)date_timetuple, METH_NOARGS, + {"timetuple", date_timetuple, METH_NOARGS, PyDoc_STR("Return time tuple, compatible with time.localtime().")}, - {"isocalendar", (PyCFunction)date_isocalendar, METH_NOARGS, + {"isocalendar", date_isocalendar, METH_NOARGS, PyDoc_STR("Return a named tuple containing ISO year, week number, and " "weekday.")}, - {"isoformat", (PyCFunction)date_isoformat, METH_NOARGS, + {"isoformat", date_isoformat, METH_NOARGS, PyDoc_STR("Return string in ISO 8601 format, YYYY-MM-DD.")}, - {"isoweekday", (PyCFunction)date_isoweekday, METH_NOARGS, + {"isoweekday", date_isoweekday, METH_NOARGS, PyDoc_STR("Return the day of the week represented by the date.\n" "Monday == 1 ... Sunday == 7")}, - {"toordinal", (PyCFunction)date_toordinal, METH_NOARGS, + {"toordinal", date_toordinal, METH_NOARGS, PyDoc_STR("Return proleptic Gregorian ordinal. January 1 of year " "1 is day 1.")}, - {"weekday", (PyCFunction)date_weekday, METH_NOARGS, + {"weekday", date_weekday, METH_NOARGS, PyDoc_STR("Return the day of the week represented by the date.\n" "Monday == 0 ... Sunday == 6")}, @@ -3935,7 +3951,7 @@ static PyMethodDef date_methods[] = { {"__replace__", _PyCFunction_CAST(datetime_date_replace), METH_FASTCALL | METH_KEYWORDS, PyDoc_STR("__replace__($self, /, **changes)\n--\n\nThe same as replace().")}, - {"__reduce__", (PyCFunction)date_reduce, METH_NOARGS, + {"__reduce__", date_reduce, METH_NOARGS, PyDoc_STR("__reduce__() -> (cls, state)")}, {NULL, NULL} @@ -3967,13 +3983,13 @@ static PyTypeObject PyDateTime_DateType = { 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_as_async */ - (reprfunc)date_repr, /* tp_repr */ + date_repr, /* tp_repr */ &date_as_number, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ - (hashfunc)date_hash, /* tp_hash */ + date_hash, /* tp_hash */ 0, /* tp_call */ - (reprfunc)date_str, /* tp_str */ + date_str, /* tp_str */ PyObject_GenericGetAttr, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ @@ -4028,19 +4044,19 @@ tzinfo_nogo(const char* methodname) /* Methods. A subclass must implement these. */ static PyObject * -tzinfo_tzname(PyDateTime_TZInfo *self, PyObject *dt) +tzinfo_tzname(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(dt)) { return tzinfo_nogo("tzname"); } static PyObject * -tzinfo_utcoffset(PyDateTime_TZInfo *self, PyObject *dt) +tzinfo_utcoffset(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(dt)) { return tzinfo_nogo("utcoffset"); } static PyObject * -tzinfo_dst(PyDateTime_TZInfo *self, PyObject *dt) +tzinfo_dst(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(dt)) { return tzinfo_nogo("dst"); } @@ -4053,7 +4069,7 @@ static PyObject *datetime_utcoffset(PyObject *self, PyObject *); static PyObject *datetime_dst(PyObject *self, PyObject *); static PyObject * -tzinfo_fromutc(PyDateTime_TZInfo *self, PyObject *dt) +tzinfo_fromutc(PyObject *self, PyObject *dt) { PyObject *result = NULL; PyObject *off = NULL, *dst = NULL; @@ -4064,7 +4080,7 @@ tzinfo_fromutc(PyDateTime_TZInfo *self, PyObject *dt) "fromutc: argument must be a datetime"); return NULL; } - if (GET_DT_TZINFO(dt) != (PyObject *)self) { + if (GET_DT_TZINFO(dt) != self) { PyErr_SetString(PyExc_ValueError, "fromutc: dt.tzinfo " "is not self"); return NULL; @@ -4101,7 +4117,7 @@ tzinfo_fromutc(PyDateTime_TZInfo *self, PyObject *dt) goto Fail; if (dst == Py_None) goto Inconsistent; - if (delta_bool((PyDateTime_Delta *)dst) != 0) { + if (delta_bool(dst) != 0) { Py_SETREF(result, add_datetime_timedelta((PyDateTime_DateTime *)result, (PyDateTime_Delta *)dst, 1)); if (result == NULL) @@ -4131,7 +4147,7 @@ tzinfo_fromutc(PyDateTime_TZInfo *self, PyObject *dt) */ static PyObject * -tzinfo_reduce(PyObject *self, PyObject *Py_UNUSED(ignored)) +tzinfo_reduce(PyObject *self, PyObject *Py_UNUSED(dummy)) { PyObject *args, *state; PyObject *getinitargs; @@ -4161,20 +4177,20 @@ tzinfo_reduce(PyObject *self, PyObject *Py_UNUSED(ignored)) static PyMethodDef tzinfo_methods[] = { - {"tzname", (PyCFunction)tzinfo_tzname, METH_O, + {"tzname", tzinfo_tzname, METH_O, PyDoc_STR("datetime -> string name of time zone.")}, - {"utcoffset", (PyCFunction)tzinfo_utcoffset, METH_O, + {"utcoffset", tzinfo_utcoffset, METH_O, PyDoc_STR("datetime -> timedelta showing offset from UTC, negative " "values indicating West of UTC")}, - {"dst", (PyCFunction)tzinfo_dst, METH_O, + {"dst", tzinfo_dst, METH_O, PyDoc_STR("datetime -> DST offset as timedelta positive east of UTC.")}, - {"fromutc", (PyCFunction)tzinfo_fromutc, METH_O, + {"fromutc", tzinfo_fromutc, METH_O, PyDoc_STR("datetime in UTC -> datetime in local time.")}, - {"__reduce__", tzinfo_reduce, METH_NOARGS, + {"__reduce__", tzinfo_reduce, METH_NOARGS, PyDoc_STR("-> (cls, state)")}, {NULL, NULL} @@ -4240,29 +4256,32 @@ timezone_new(PyTypeObject *type, PyObject *args, PyObject *kw) } static void -timezone_dealloc(PyDateTime_TimeZone *self) +timezone_dealloc(PyObject *op) { + PyDateTime_TimeZone *self = PyTimeZone_CAST(op); Py_CLEAR(self->offset); Py_CLEAR(self->name); - Py_TYPE(self)->tp_free((PyObject *)self); + Py_TYPE(self)->tp_free(self); } static PyObject * -timezone_richcompare(PyDateTime_TimeZone *self, - PyDateTime_TimeZone *other, int op) +timezone_richcompare(PyObject *self, PyObject *other, int op) { if (op != Py_EQ && op != Py_NE) Py_RETURN_NOTIMPLEMENTED; if (!PyTimezone_Check(other)) { Py_RETURN_NOTIMPLEMENTED; } - return delta_richcompare(self->offset, other->offset, op); + PyDateTime_TimeZone *lhs = PyTimeZone_CAST(self); + PyDateTime_TimeZone *rhs = PyTimeZone_CAST(other); + return delta_richcompare(lhs->offset, rhs->offset, op); } static Py_hash_t -timezone_hash(PyDateTime_TimeZone *self) +timezone_hash(PyObject *op) { - return delta_hash((PyDateTime_Delta *)self->offset); + PyDateTime_TimeZone *self = PyTimeZone_CAST(op); + return delta_hash(self->offset); } /* Check argument type passed to tzname, utcoffset, or dst methods. @@ -4280,13 +4299,14 @@ _timezone_check_argument(PyObject *dt, const char *meth) } static PyObject * -timezone_repr(PyDateTime_TimeZone *self) +timezone_repr(PyObject *op) { /* Note that although timezone is not subclassable, it is convenient to use Py_TYPE(self)->tp_name here. */ + PyDateTime_TimeZone *self = PyTimeZone_CAST(op); const char *type_name = Py_TYPE(self)->tp_name; - if ((PyObject *)self == CONST_UTC(NO_STATE)) { + if (op == CONST_UTC(NO_STATE)) { return PyUnicode_FromFormat("%s.utc", type_name); } @@ -4297,10 +4317,10 @@ timezone_repr(PyDateTime_TimeZone *self) self->name); } - static PyObject * -timezone_str(PyDateTime_TimeZone *self) +timezone_str(PyObject *op) { + PyDateTime_TimeZone *self = PyTimeZone_CAST(op); int hours, minutes, seconds, microseconds; PyObject *offset; char sign; @@ -4318,7 +4338,7 @@ timezone_str(PyDateTime_TimeZone *self) /* Offset is normalized, so it is negative if days < 0 */ if (GET_TD_DAYS(self->offset) < 0) { sign = '-'; - offset = delta_negative((PyDateTime_Delta *)self->offset); + offset = delta_negative(self->offset); if (offset == NULL) return NULL; } @@ -4345,25 +4365,26 @@ timezone_str(PyDateTime_TimeZone *self) } static PyObject * -timezone_tzname(PyDateTime_TimeZone *self, PyObject *dt) +timezone_tzname(PyObject *op, PyObject *dt) { if (_timezone_check_argument(dt, "tzname") == -1) return NULL; - return timezone_str(self); + return timezone_str(op); } static PyObject * -timezone_utcoffset(PyDateTime_TimeZone *self, PyObject *dt) +timezone_utcoffset(PyObject *op, PyObject *dt) { if (_timezone_check_argument(dt, "utcoffset") == -1) return NULL; + PyDateTime_TimeZone *self = PyTimeZone_CAST(op); return Py_NewRef(self->offset); } static PyObject * -timezone_dst(PyObject *self, PyObject *dt) +timezone_dst(PyObject *op, PyObject *dt) { if (_timezone_check_argument(dt, "dst") == -1) return NULL; @@ -4372,44 +4393,48 @@ timezone_dst(PyObject *self, PyObject *dt) } static PyObject * -timezone_fromutc(PyDateTime_TimeZone *self, PyDateTime_DateTime *dt) +timezone_fromutc(PyObject *op, PyObject *arg) { - if (!PyDateTime_Check(dt)) { + if (!PyDateTime_Check(arg)) { PyErr_SetString(PyExc_TypeError, "fromutc: argument must be a datetime"); return NULL; } - if (!HASTZINFO(dt) || dt->tzinfo != (PyObject *)self) { + + PyDateTime_DateTime *dt = (PyDateTime_DateTime *)arg; // fast safe cast + if (!HASTZINFO(dt) || dt->tzinfo != op) { PyErr_SetString(PyExc_ValueError, "fromutc: dt.tzinfo is not self"); return NULL; } + PyDateTime_TimeZone *self = PyTimeZone_CAST(op); return add_datetime_timedelta(dt, (PyDateTime_Delta *)self->offset, 1); } static PyObject * -timezone_getinitargs(PyDateTime_TimeZone *self, PyObject *Py_UNUSED(ignored)) +timezone_getinitargs(PyObject *op, PyObject *Py_UNUSED(dummy)) { + PyDateTime_TimeZone *self = PyTimeZone_CAST(op); if (self->name == NULL) return PyTuple_Pack(1, self->offset); return PyTuple_Pack(2, self->offset, self->name); } static PyMethodDef timezone_methods[] = { - {"tzname", (PyCFunction)timezone_tzname, METH_O, + {"tzname", timezone_tzname, METH_O, PyDoc_STR("If name is specified when timezone is created, returns the name." " Otherwise returns offset as 'UTC(+|-)HH:MM'.")}, - {"utcoffset", (PyCFunction)timezone_utcoffset, METH_O, + {"utcoffset", timezone_utcoffset, METH_O, PyDoc_STR("Return fixed offset.")}, - {"dst", (PyCFunction)timezone_dst, METH_O, + {"dst", timezone_dst, METH_O, PyDoc_STR("Return None.")}, - {"fromutc", (PyCFunction)timezone_fromutc, METH_O, + {"fromutc", timezone_fromutc, METH_O, PyDoc_STR("datetime in UTC -> datetime in local time.")}, - {"__getinitargs__", (PyCFunction)timezone_getinitargs, METH_NOARGS, + {"__getinitargs__", timezone_getinitargs, METH_NOARGS, PyDoc_STR("pickle support")}, {NULL, NULL} @@ -4423,18 +4448,18 @@ static PyTypeObject PyDateTime_TimeZoneType = { "datetime.timezone", /* tp_name */ sizeof(PyDateTime_TimeZone), /* tp_basicsize */ 0, /* tp_itemsize */ - (destructor)timezone_dealloc, /* tp_dealloc */ + timezone_dealloc, /* tp_dealloc */ 0, /* tp_vectorcall_offset */ 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_as_async */ - (reprfunc)timezone_repr, /* tp_repr */ + timezone_repr, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ - (hashfunc)timezone_hash, /* tp_hash */ + timezone_hash, /* tp_hash */ 0, /* tp_call */ - (reprfunc)timezone_str, /* tp_str */ + timezone_str, /* tp_str */ 0, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ @@ -4442,7 +4467,7 @@ static PyTypeObject PyDateTime_TimeZoneType = { timezone_doc, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ - (richcmpfunc)timezone_richcompare,/* tp_richcompare */ + timezone_richcompare, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ @@ -4484,50 +4509,56 @@ look_up_timezone(PyObject *offset, PyObject *name) */ static PyObject * -time_hour(PyDateTime_Time *self, void *unused) +time_hour(PyObject *op, void *Py_UNUSED(closure)) { + PyDateTime_Time *self = PyTime_CAST(op); return PyLong_FromLong(TIME_GET_HOUR(self)); } static PyObject * -time_minute(PyDateTime_Time *self, void *unused) +time_minute(PyObject *op, void *Py_UNUSED(closure)) { + PyDateTime_Time *self = PyTime_CAST(op); return PyLong_FromLong(TIME_GET_MINUTE(self)); } /* The name time_second conflicted with some platform header file. */ static PyObject * -py_time_second(PyDateTime_Time *self, void *unused) +py_time_second(PyObject *op, void *Py_UNUSED(closure)) { + PyDateTime_Time *self = PyTime_CAST(op); return PyLong_FromLong(TIME_GET_SECOND(self)); } static PyObject * -time_microsecond(PyDateTime_Time *self, void *unused) +time_microsecond(PyObject *op, void *Py_UNUSED(closure)) { + PyDateTime_Time *self = PyTime_CAST(op); return PyLong_FromLong(TIME_GET_MICROSECOND(self)); } static PyObject * -time_tzinfo(PyDateTime_Time *self, void *unused) +time_tzinfo(PyObject *op, void *Py_UNUSED(closure)) { + PyDateTime_Time *self = PyTime_CAST(op); PyObject *result = HASTZINFO(self) ? self->tzinfo : Py_None; return Py_NewRef(result); } static PyObject * -time_fold(PyDateTime_Time *self, void *unused) +time_fold(PyObject *op, void *Py_UNUSED(closure)) { + PyDateTime_Time *self = PyTime_CAST(op); return PyLong_FromLong(TIME_GET_FOLD(self)); } static PyGetSetDef time_getset[] = { - {"hour", (getter)time_hour}, - {"minute", (getter)time_minute}, - {"second", (getter)py_time_second}, - {"microsecond", (getter)time_microsecond}, - {"tzinfo", (getter)time_tzinfo}, - {"fold", (getter)time_fold}, + {"hour", time_hour}, + {"minute", time_minute}, + {"second", py_time_second}, + {"microsecond", time_microsecond}, + {"tzinfo", time_tzinfo}, + {"fold", time_fold}, {NULL} }; @@ -4652,12 +4683,13 @@ time_strptime(PyObject *cls, PyObject *args) */ static void -time_dealloc(PyDateTime_Time *self) +time_dealloc(PyObject *op) { + PyDateTime_Time *self = PyTime_CAST(op); if (HASTZINFO(self)) { Py_XDECREF(self->tzinfo); } - Py_TYPE(self)->tp_free((PyObject *)self); + Py_TYPE(self)->tp_free(self); } /* @@ -4666,17 +4698,20 @@ time_dealloc(PyDateTime_Time *self) /* These are all METH_NOARGS, so don't need to check the arglist. */ static PyObject * -time_utcoffset(PyObject *self, PyObject *unused) { +time_utcoffset(PyObject *op, PyObject *Py_UNUSED(dummy)) { + PyDateTime_Time *self = PyTime_CAST(op); return call_utcoffset(GET_TIME_TZINFO(self), Py_None); } static PyObject * -time_dst(PyObject *self, PyObject *unused) { +time_dst(PyObject *op, PyObject *Py_UNUSED(dummy)) { + PyDateTime_Time *self = PyTime_CAST(op); return call_dst(GET_TIME_TZINFO(self), Py_None); } static PyObject * -time_tzname(PyDateTime_Time *self, PyObject *unused) { +time_tzname(PyObject *op, PyObject *Py_UNUSED(dummy)) { + PyDateTime_Time *self = PyTime_CAST(op); return call_tzname(GET_TIME_TZINFO(self), Py_None); } @@ -4685,8 +4720,9 @@ time_tzname(PyDateTime_Time *self, PyObject *unused) { */ static PyObject * -time_repr(PyDateTime_Time *self) +time_repr(PyObject *op) { + PyDateTime_Time *self = PyTime_CAST(op); const char *type_name = Py_TYPE(self)->tp_name; int h = TIME_GET_HOUR(self); int m = TIME_GET_MINUTE(self); @@ -4711,17 +4747,19 @@ time_repr(PyDateTime_Time *self) } static PyObject * -time_str(PyDateTime_Time *self) +time_str(PyObject *op) { - return PyObject_CallMethodNoArgs((PyObject *)self, &_Py_ID(isoformat)); + return PyObject_CallMethodNoArgs(op, &_Py_ID(isoformat)); } static PyObject * -time_isoformat(PyDateTime_Time *self, PyObject *args, PyObject *kw) +time_isoformat(PyObject *op, PyObject *args, PyObject *kw) { char buf[100]; const char *timespec = NULL; static char *keywords[] = {"timespec", NULL}; + PyDateTime_Time *self = PyTime_CAST(op); + PyObject *result; int us = TIME_GET_MICROSECOND(self); static const char *specs[][2] = { @@ -4782,12 +4820,13 @@ time_isoformat(PyDateTime_Time *self, PyObject *args, PyObject *kw) } static PyObject * -time_strftime(PyDateTime_Time *self, PyObject *args, PyObject *kw) +time_strftime(PyObject *op, PyObject *args, PyObject *kw) { PyObject *result; PyObject *tuple; PyObject *format; static char *keywords[] = {"format", NULL}; + PyDateTime_Time *self = PyTime_CAST(op); if (! PyArg_ParseTupleAndKeywords(args, kw, "U:strftime", keywords, &format)) @@ -4888,8 +4927,9 @@ time_richcompare(PyObject *self, PyObject *other, int op) } static Py_hash_t -time_hash(PyDateTime_Time *self) +time_hash(PyObject *op) { + PyDateTime_Time *self = PyTime_CAST(op); if (self->hashcode == -1) { PyObject *offset, *self0; if (TIME_GET_FOLD(self)) { @@ -5065,18 +5105,20 @@ time_getstate(PyDateTime_Time *self, int proto) } static PyObject * -time_reduce_ex(PyDateTime_Time *self, PyObject *args) +time_reduce_ex(PyObject *op, PyObject *args) { int proto; if (!PyArg_ParseTuple(args, "i:__reduce_ex__", &proto)) return NULL; + PyDateTime_Time *self = PyTime_CAST(op); return Py_BuildValue("(ON)", Py_TYPE(self), time_getstate(self, proto)); } static PyObject * -time_reduce(PyDateTime_Time *self, PyObject *arg) +time_reduce(PyObject *op, PyObject *Py_UNUSED(dummy)) { + PyDateTime_Time *self = PyTime_CAST(op); return Py_BuildValue("(ON)", Py_TYPE(self), time_getstate(self, 2)); } @@ -5084,14 +5126,14 @@ static PyMethodDef time_methods[] = { /* Class method: */ - {"strptime", (PyCFunction)time_strptime, + {"strptime", time_strptime, METH_VARARGS | METH_CLASS, PyDoc_STR("string, format -> new time parsed from a string " "(like time.strptime()).")}, /* Instance methods: */ - {"isoformat", _PyCFunction_CAST(time_isoformat), METH_VARARGS | METH_KEYWORDS, + {"isoformat", _PyCFunction_CAST(time_isoformat), METH_VARARGS | METH_KEYWORDS, PyDoc_STR("Return string in ISO 8601 format, [HH[:MM[:SS[.mmm[uuu]]]]]" "[+HH:MM].\n\n" "The optional argument timespec specifies the number " @@ -5099,19 +5141,19 @@ static PyMethodDef time_methods[] = { "options are 'auto', 'hours', 'minutes',\n'seconds', " "'milliseconds' and 'microseconds'.\n")}, - {"strftime", _PyCFunction_CAST(time_strftime), METH_VARARGS | METH_KEYWORDS, + {"strftime", _PyCFunction_CAST(time_strftime), METH_VARARGS | METH_KEYWORDS, PyDoc_STR("format -> strftime() style string.")}, - {"__format__", (PyCFunction)date_format, METH_VARARGS, + {"__format__", date_format, METH_VARARGS, PyDoc_STR("Formats self with strftime.")}, - {"utcoffset", (PyCFunction)time_utcoffset, METH_NOARGS, + {"utcoffset", time_utcoffset, METH_NOARGS, PyDoc_STR("Return self.tzinfo.utcoffset(self).")}, - {"tzname", (PyCFunction)time_tzname, METH_NOARGS, + {"tzname", time_tzname, METH_NOARGS, PyDoc_STR("Return self.tzinfo.tzname(self).")}, - {"dst", (PyCFunction)time_dst, METH_NOARGS, + {"dst", time_dst, METH_NOARGS, PyDoc_STR("Return self.tzinfo.dst(self).")}, DATETIME_TIME_REPLACE_METHODDEF @@ -5119,13 +5161,13 @@ static PyMethodDef time_methods[] = { {"__replace__", _PyCFunction_CAST(datetime_time_replace), METH_FASTCALL | METH_KEYWORDS, PyDoc_STR("__replace__($self, /, **changes)\n--\n\nThe same as replace().")}, - {"fromisoformat", (PyCFunction)time_fromisoformat, METH_O | METH_CLASS, + {"fromisoformat", time_fromisoformat, METH_O | METH_CLASS, PyDoc_STR("string -> time from a string in ISO 8601 format")}, - {"__reduce_ex__", (PyCFunction)time_reduce_ex, METH_VARARGS, + {"__reduce_ex__", time_reduce_ex, METH_VARARGS, PyDoc_STR("__reduce_ex__(proto) -> (cls, state)")}, - {"__reduce__", (PyCFunction)time_reduce, METH_NOARGS, + {"__reduce__", time_reduce, METH_NOARGS, PyDoc_STR("__reduce__() -> (cls, state)")}, {NULL, NULL} @@ -5142,18 +5184,18 @@ static PyTypeObject PyDateTime_TimeType = { "datetime.time", /* tp_name */ sizeof(PyDateTime_Time), /* tp_basicsize */ 0, /* tp_itemsize */ - (destructor)time_dealloc, /* tp_dealloc */ + time_dealloc, /* tp_dealloc */ 0, /* tp_vectorcall_offset */ 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_as_async */ - (reprfunc)time_repr, /* tp_repr */ + time_repr, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ - (hashfunc)time_hash, /* tp_hash */ + time_hash, /* tp_hash */ 0, /* tp_call */ - (reprfunc)time_str, /* tp_str */ + time_str, /* tp_str */ PyObject_GenericGetAttr, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ @@ -5188,49 +5230,55 @@ static PyTypeObject PyDateTime_TimeType = { */ static PyObject * -datetime_hour(PyDateTime_DateTime *self, void *unused) +datetime_hour(PyObject *op, void *Py_UNUSED(closure)) { + PyDateTime_DateTime *self = PyDateTime_CAST(op); return PyLong_FromLong(DATE_GET_HOUR(self)); } static PyObject * -datetime_minute(PyDateTime_DateTime *self, void *unused) +datetime_minute(PyObject *op, void *Py_UNUSED(closure)) { + PyDateTime_DateTime *self = PyDateTime_CAST(op); return PyLong_FromLong(DATE_GET_MINUTE(self)); } static PyObject * -datetime_second(PyDateTime_DateTime *self, void *unused) +datetime_second(PyObject *op, void *Py_UNUSED(closure)) { + PyDateTime_DateTime *self = PyDateTime_CAST(op); return PyLong_FromLong(DATE_GET_SECOND(self)); } static PyObject * -datetime_microsecond(PyDateTime_DateTime *self, void *unused) +datetime_microsecond(PyObject *op, void *Py_UNUSED(closure)) { + PyDateTime_DateTime *self = PyDateTime_CAST(op); return PyLong_FromLong(DATE_GET_MICROSECOND(self)); } static PyObject * -datetime_tzinfo(PyDateTime_DateTime *self, void *unused) +datetime_tzinfo(PyObject *op, void *Py_UNUSED(closure)) { + PyDateTime_DateTime *self = PyDateTime_CAST(op); PyObject *result = HASTZINFO(self) ? self->tzinfo : Py_None; return Py_NewRef(result); } static PyObject * -datetime_fold(PyDateTime_DateTime *self, void *unused) +datetime_fold(PyObject *op, void *Py_UNUSED(closure)) { + PyDateTime_DateTime *self = PyDateTime_CAST(op); return PyLong_FromLong(DATE_GET_FOLD(self)); } static PyGetSetDef datetime_getset[] = { - {"hour", (getter)datetime_hour}, - {"minute", (getter)datetime_minute}, - {"second", (getter)datetime_second}, - {"microsecond", (getter)datetime_microsecond}, - {"tzinfo", (getter)datetime_tzinfo}, - {"fold", (getter)datetime_fold}, + {"hour", datetime_hour}, + {"minute", datetime_minute}, + {"second", datetime_second}, + {"microsecond", datetime_microsecond}, + {"tzinfo", datetime_tzinfo}, + {"fold", datetime_fold}, {NULL} }; @@ -5934,12 +5982,13 @@ datetime_fromisoformat(PyObject *cls, PyObject *dtstr) */ static void -datetime_dealloc(PyDateTime_DateTime *self) +datetime_dealloc(PyObject *op) { + PyDateTime_DateTime *self = PyDateTime_CAST(op); if (HASTZINFO(self)) { Py_XDECREF(self->tzinfo); } - Py_TYPE(self)->tp_free((PyObject *)self); + Py_TYPE(self)->tp_free(self); } /* @@ -5948,18 +5997,21 @@ datetime_dealloc(PyDateTime_DateTime *self) /* These are all METH_NOARGS, so don't need to check the arglist. */ static PyObject * -datetime_utcoffset(PyObject *self, PyObject *unused) { - return call_utcoffset(GET_DT_TZINFO(self), self); +datetime_utcoffset(PyObject *op, PyObject *Py_UNUSED(dummy)) { + PyDateTime_DateTime *self = PyDateTime_CAST(op); + return call_utcoffset(GET_DT_TZINFO(self), op); } static PyObject * -datetime_dst(PyObject *self, PyObject *unused) { - return call_dst(GET_DT_TZINFO(self), self); +datetime_dst(PyObject *op, PyObject *Py_UNUSED(dummy)) { + PyDateTime_DateTime *self = PyDateTime_CAST(op); + return call_dst(GET_DT_TZINFO(self), op); } static PyObject * -datetime_tzname(PyObject *self, PyObject *unused) { - return call_tzname(GET_DT_TZINFO(self), self); +datetime_tzname(PyObject *op, PyObject *Py_UNUSED(dummy)) { + PyDateTime_DateTime *self = PyDateTime_CAST(op); + return call_tzname(GET_DT_TZINFO(self), op); } /* @@ -6107,8 +6159,9 @@ datetime_subtract(PyObject *left, PyObject *right) /* Various ways to turn a datetime into a string. */ static PyObject * -datetime_repr(PyDateTime_DateTime *self) +datetime_repr(PyObject *op) { + PyDateTime_DateTime *self = PyDateTime_CAST(op); const char *type_name = Py_TYPE(self)->tp_name; PyObject *baserepr; @@ -6144,25 +6197,26 @@ datetime_repr(PyDateTime_DateTime *self) } static PyObject * -datetime_str(PyDateTime_DateTime *self) +datetime_str(PyObject *op) { PyObject *space = PyUnicode_FromString(" "); if (space == NULL) { return NULL; } - PyObject *res = PyObject_CallMethodOneArg((PyObject *)self, - &_Py_ID(isoformat), space); + PyObject *res = PyObject_CallMethodOneArg(op, &_Py_ID(isoformat), space); Py_DECREF(space); return res; } static PyObject * -datetime_isoformat(PyDateTime_DateTime *self, PyObject *args, PyObject *kw) +datetime_isoformat(PyObject *op, PyObject *args, PyObject *kw) { int sep = 'T'; char *timespec = NULL; static char *keywords[] = {"sep", "timespec", NULL}; char buffer[100]; + PyDateTime_DateTime *self = PyDateTime_CAST(op); + PyObject *result = NULL; int us = DATE_GET_MICROSECOND(self); static const char *specs[][2] = { @@ -6214,8 +6268,7 @@ datetime_isoformat(PyDateTime_DateTime *self, PyObject *args, PyObject *kw) return result; /* We need to append the UTC offset. */ - if (format_utcoffset(buffer, sizeof(buffer), ":", self->tzinfo, - (PyObject *)self) < 0) { + if (format_utcoffset(buffer, sizeof(buffer), ":", self->tzinfo, op) < 0) { Py_DECREF(result); return NULL; } @@ -6224,9 +6277,10 @@ datetime_isoformat(PyDateTime_DateTime *self, PyObject *args, PyObject *kw) } static PyObject * -datetime_ctime(PyDateTime_DateTime *self, PyObject *Py_UNUSED(ignored)) +datetime_ctime(PyObject *op, PyObject *Py_UNUSED(dummy)) { - return format_ctime((PyDateTime_Date *)self, + PyDateTime_DateTime *self = PyDateTime_CAST(op); + return format_ctime(op, DATE_GET_HOUR(self), DATE_GET_MINUTE(self), DATE_GET_SECOND(self)); @@ -6380,8 +6434,9 @@ datetime_richcompare(PyObject *self, PyObject *other, int op) } static Py_hash_t -datetime_hash(PyDateTime_DateTime *self) +datetime_hash(PyObject *op) { + PyDateTime_DateTime *self = PyDateTime_CAST(op); if (self->hashcode == -1) { PyObject *offset, *self0; if (DATE_GET_FOLD(self)) { @@ -6604,9 +6659,10 @@ local_timezone_from_local(PyDateTime_DateTime *local_dt) return local_timezone_from_timestamp(timestamp); } -static PyDateTime_DateTime * -datetime_astimezone(PyDateTime_DateTime *self, PyObject *args, PyObject *kw) +static PyObject * +datetime_astimezone(PyObject *op, PyObject *args, PyObject *kw) { + PyDateTime_DateTime *self = PyDateTime_CAST(op); PyDateTime_DateTime *result; PyObject *offset; PyObject *temp; @@ -6633,7 +6689,7 @@ datetime_astimezone(PyDateTime_DateTime *self, PyObject *args, PyObject *kw) /* Conversion to self's own time zone is a NOP. */ if (self_tzinfo == tzinfo) { Py_DECREF(self_tzinfo); - return (PyDateTime_DateTime*)Py_NewRef(self); + return Py_NewRef(self); } /* Convert self to UTC. */ @@ -6698,23 +6754,24 @@ datetime_astimezone(PyDateTime_DateTime *self, PyObject *args, PyObject *kw) PyObject_CallMethodOneArg(tzinfo, &_Py_ID(fromutc), temp); Py_DECREF(temp); - return result; + return (PyObject *)result; } static PyObject * -datetime_timetuple(PyDateTime_DateTime *self, PyObject *Py_UNUSED(ignored)) +datetime_timetuple(PyObject *op, PyObject *Py_UNUSED(dummy)) { + PyDateTime_DateTime *self = PyDateTime_CAST(op); int dstflag = -1; if (HASTZINFO(self) && self->tzinfo != Py_None) { PyObject * dst; - dst = call_dst(self->tzinfo, (PyObject *)self); + dst = call_dst(self->tzinfo, op); if (dst == NULL) return NULL; if (dst != Py_None) - dstflag = delta_bool((PyDateTime_Delta *)dst); + dstflag = delta_bool(dst); Py_DECREF(dst); } return build_struct_time(GET_YEAR(self), @@ -6777,8 +6834,9 @@ local_to_seconds(int year, int month, int day, #define EPOCH_SECONDS (719163LL * 24 * 60 * 60) static PyObject * -datetime_timestamp(PyDateTime_DateTime *self, PyObject *Py_UNUSED(ignored)) +datetime_timestamp(PyObject *op, PyObject *Py_UNUSED(dummy)) { + PyDateTime_DateTime *self = PyDateTime_CAST(op); PyObject *result; if (HASTZINFO(self) && self->tzinfo != Py_None) { @@ -6786,7 +6844,7 @@ datetime_timestamp(PyDateTime_DateTime *self, PyObject *Py_UNUSED(ignored)) datetime_state *st = GET_CURRENT_STATE(current_mod); PyObject *delta; - delta = datetime_subtract((PyObject *)self, CONST_EPOCH(st)); + delta = datetime_subtract(op, CONST_EPOCH(st)); RELEASE_CURRENT_STATE(st, current_mod); if (delta == NULL) return NULL; @@ -6811,16 +6869,18 @@ datetime_timestamp(PyDateTime_DateTime *self, PyObject *Py_UNUSED(ignored)) } static PyObject * -datetime_getdate(PyDateTime_DateTime *self, PyObject *Py_UNUSED(ignored)) +datetime_getdate(PyObject *op, PyObject *Py_UNUSED(dummy)) { + PyDateTime_DateTime *self = PyDateTime_CAST(op); return new_date(GET_YEAR(self), GET_MONTH(self), GET_DAY(self)); } static PyObject * -datetime_gettime(PyDateTime_DateTime *self, PyObject *Py_UNUSED(ignored)) +datetime_gettime(PyObject *op, PyObject *Py_UNUSED(dummy)) { + PyDateTime_DateTime *self = PyDateTime_CAST(op); return new_time(DATE_GET_HOUR(self), DATE_GET_MINUTE(self), DATE_GET_SECOND(self), @@ -6830,8 +6890,9 @@ datetime_gettime(PyDateTime_DateTime *self, PyObject *Py_UNUSED(ignored)) } static PyObject * -datetime_gettimetz(PyDateTime_DateTime *self, PyObject *Py_UNUSED(ignored)) +datetime_gettimetz(PyObject *op, PyObject *Py_UNUSED(dummy)) { + PyDateTime_DateTime *self = PyDateTime_CAST(op); return new_time(DATE_GET_HOUR(self), DATE_GET_MINUTE(self), DATE_GET_SECOND(self), @@ -6841,11 +6902,12 @@ datetime_gettimetz(PyDateTime_DateTime *self, PyObject *Py_UNUSED(ignored)) } static PyObject * -datetime_utctimetuple(PyDateTime_DateTime *self, PyObject *Py_UNUSED(ignored)) +datetime_utctimetuple(PyObject *op, PyObject *Py_UNUSED(dummy)) { int y, m, d, hh, mm, ss; PyObject *tzinfo; PyDateTime_DateTime *utcself; + PyDateTime_DateTime *self = PyDateTime_CAST(op); tzinfo = GET_DT_TZINFO(self); if (tzinfo == Py_None) { @@ -6908,19 +6970,23 @@ datetime_getstate(PyDateTime_DateTime *self, int proto) } static PyObject * -datetime_reduce_ex(PyDateTime_DateTime *self, PyObject *args) +datetime_reduce_ex(PyObject *op, PyObject *args) { int proto; if (!PyArg_ParseTuple(args, "i:__reduce_ex__", &proto)) return NULL; - return Py_BuildValue("(ON)", Py_TYPE(self), datetime_getstate(self, proto)); + PyDateTime_DateTime *self = PyDateTime_CAST(op); + return Py_BuildValue("(ON)", Py_TYPE(self), + datetime_getstate(self, proto)); } static PyObject * -datetime_reduce(PyDateTime_DateTime *self, PyObject *arg) +datetime_reduce(PyObject *op, PyObject *Py_UNUSED(arg)) { - return Py_BuildValue("(ON)", Py_TYPE(self), datetime_getstate(self, 2)); + PyDateTime_DateTime *self = PyDateTime_CAST(op); + return Py_BuildValue("(ON)", Py_TYPE(self), + datetime_getstate(self, 2)); } static PyMethodDef datetime_methods[] = { @@ -6929,7 +6995,7 @@ static PyMethodDef datetime_methods[] = { DATETIME_DATETIME_NOW_METHODDEF - {"utcnow", (PyCFunction)datetime_utcnow, + {"utcnow", datetime_utcnow, METH_NOARGS | METH_CLASS, PyDoc_STR("Return a new datetime representing UTC day and time.")}, @@ -6937,11 +7003,11 @@ static PyMethodDef datetime_methods[] = { METH_VARARGS | METH_KEYWORDS | METH_CLASS, PyDoc_STR("timestamp[, tz] -> tz's local time from POSIX timestamp.")}, - {"utcfromtimestamp", (PyCFunction)datetime_utcfromtimestamp, + {"utcfromtimestamp", datetime_utcfromtimestamp, METH_VARARGS | METH_CLASS, PyDoc_STR("Construct a naive UTC datetime from a POSIX timestamp.")}, - {"strptime", (PyCFunction)datetime_strptime, + {"strptime", datetime_strptime, METH_VARARGS | METH_CLASS, PyDoc_STR("string, format -> new datetime parsed from a string " "(like time.strptime()).")}, @@ -6950,34 +7016,34 @@ static PyMethodDef datetime_methods[] = { METH_VARARGS | METH_KEYWORDS | METH_CLASS, PyDoc_STR("date, time -> datetime with same date and time fields")}, - {"fromisoformat", (PyCFunction)datetime_fromisoformat, + {"fromisoformat", datetime_fromisoformat, METH_O | METH_CLASS, PyDoc_STR("string -> datetime from a string in most ISO 8601 formats")}, /* Instance methods: */ - {"date", (PyCFunction)datetime_getdate, METH_NOARGS, + {"date", datetime_getdate, METH_NOARGS, PyDoc_STR("Return date object with same year, month and day.")}, - {"time", (PyCFunction)datetime_gettime, METH_NOARGS, + {"time", datetime_gettime, METH_NOARGS, PyDoc_STR("Return time object with same time but with tzinfo=None.")}, - {"timetz", (PyCFunction)datetime_gettimetz, METH_NOARGS, + {"timetz", datetime_gettimetz, METH_NOARGS, PyDoc_STR("Return time object with same time and tzinfo.")}, - {"ctime", (PyCFunction)datetime_ctime, METH_NOARGS, + {"ctime", datetime_ctime, METH_NOARGS, PyDoc_STR("Return ctime() style string.")}, - {"timetuple", (PyCFunction)datetime_timetuple, METH_NOARGS, + {"timetuple", datetime_timetuple, METH_NOARGS, PyDoc_STR("Return time tuple, compatible with time.localtime().")}, - {"timestamp", (PyCFunction)datetime_timestamp, METH_NOARGS, + {"timestamp", datetime_timestamp, METH_NOARGS, PyDoc_STR("Return POSIX timestamp as float.")}, - {"utctimetuple", (PyCFunction)datetime_utctimetuple, METH_NOARGS, + {"utctimetuple", datetime_utctimetuple, METH_NOARGS, PyDoc_STR("Return UTC time tuple, compatible with time.localtime().")}, - {"isoformat", _PyCFunction_CAST(datetime_isoformat), METH_VARARGS | METH_KEYWORDS, + {"isoformat", _PyCFunction_CAST(datetime_isoformat), METH_VARARGS | METH_KEYWORDS, PyDoc_STR("[sep] -> string in ISO 8601 format, " "YYYY-MM-DDT[HH[:MM[:SS[.mmm[uuu]]]]][+HH:MM].\n" "sep is used to separate the year from the time, and " @@ -6987,13 +7053,13 @@ static PyMethodDef datetime_methods[] = { "options are 'auto', 'hours', 'minutes',\n'seconds', " "'milliseconds' and 'microseconds'.\n")}, - {"utcoffset", (PyCFunction)datetime_utcoffset, METH_NOARGS, + {"utcoffset", datetime_utcoffset, METH_NOARGS, PyDoc_STR("Return self.tzinfo.utcoffset(self).")}, - {"tzname", (PyCFunction)datetime_tzname, METH_NOARGS, + {"tzname", datetime_tzname, METH_NOARGS, PyDoc_STR("Return self.tzinfo.tzname(self).")}, - {"dst", (PyCFunction)datetime_dst, METH_NOARGS, + {"dst", datetime_dst, METH_NOARGS, PyDoc_STR("Return self.tzinfo.dst(self).")}, DATETIME_DATETIME_REPLACE_METHODDEF @@ -7004,10 +7070,10 @@ static PyMethodDef datetime_methods[] = { {"astimezone", _PyCFunction_CAST(datetime_astimezone), METH_VARARGS | METH_KEYWORDS, PyDoc_STR("tz -> convert to local time in new timezone tz\n")}, - {"__reduce_ex__", (PyCFunction)datetime_reduce_ex, METH_VARARGS, + {"__reduce_ex__", datetime_reduce_ex, METH_VARARGS, PyDoc_STR("__reduce_ex__(proto) -> (cls, state)")}, - {"__reduce__", (PyCFunction)datetime_reduce, METH_NOARGS, + {"__reduce__", datetime_reduce, METH_NOARGS, PyDoc_STR("__reduce__() -> (cls, state)")}, {NULL, NULL} @@ -7037,18 +7103,18 @@ static PyTypeObject PyDateTime_DateTimeType = { "datetime.datetime", /* tp_name */ sizeof(PyDateTime_DateTime), /* tp_basicsize */ 0, /* tp_itemsize */ - (destructor)datetime_dealloc, /* tp_dealloc */ + datetime_dealloc, /* tp_dealloc */ 0, /* tp_vectorcall_offset */ 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_as_async */ - (reprfunc)datetime_repr, /* tp_repr */ + datetime_repr, /* tp_repr */ &datetime_as_number, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ - (hashfunc)datetime_hash, /* tp_hash */ + datetime_hash, /* tp_hash */ 0, /* tp_call */ - (reprfunc)datetime_str, /* tp_str */ + datetime_str, /* tp_str */ PyObject_GenericGetAttr, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */