Skip to content

Compiled pandas with -Wextra #56327

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 16 commits into from
Dec 9, 2023
3 changes: 2 additions & 1 deletion meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ project(
meson_version: '>=1.2.1',
default_options: [
'buildtype=release',
'c_std=c11'
'c_std=c11',
'warning_level=2',
]
)

Expand Down
10 changes: 10 additions & 0 deletions pandas/_libs/include/pandas/portable.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,13 @@ The full license is in the LICENSE file, distributed with this software.
#define isspace_ascii(c) (((c) == ' ') || (((unsigned)(c) - '\t') < 5))
#define toupper_ascii(c) ((((unsigned)(c) - 'a') < 26) ? ((c) & 0x5f) : (c))
#define tolower_ascii(c) ((((unsigned)(c) - 'A') < 26) ? ((c) | 0x20) : (c))

#define UNUSED(x) (void)(x)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just curious why this is needed

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused parameters trigger a warning, and there is no cross platform way to silence them. Gcc/clang have an unused attribute. I'm not aware of something for MSVC

Python offers a Py_UNUSED macro for this purpose too. Let me see if we can switch over to that so it's one less thing we manage


#if __has_attribute(__fallthrough__)
#define PD_FALLTHROUGH __attribute__((__fallthrough__))
#else
#define PD_FALLTHROUGH \
do { \
} while (0) /* fallthrough */
#endif
2 changes: 2 additions & 0 deletions pandas/_libs/src/datetime/pd_datetime.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ This file is derived from NumPy 1.7. See NUMPY_LICENSE.txt

#include "datetime.h"
#include "pandas/datetime/pd_datetime.h"
#include "pandas/portable.h"

static void pandas_datetime_destructor(PyObject *op) {
void *ptr = PyCapsule_GetPointer(op, PandasDateTime_CAPSULE_NAME);
Expand Down Expand Up @@ -189,6 +190,7 @@ static npy_datetime PyDateTimeToEpoch(PyObject *dt, NPY_DATETIMEUNIT base) {
}

static int pandas_datetime_exec(PyObject *module) {
UNUSED(module);
PyDateTime_IMPORT;
PandasDateTime_CAPI *capi = PyMem_Malloc(sizeof(PandasDateTime_CAPI));
if (capi == NULL) {
Expand Down
1 change: 1 addition & 0 deletions pandas/_libs/src/parser/pd_parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ static void pandas_parser_destructor(PyObject *op) {
}

static int pandas_parser_exec(PyObject *module) {
UNUSED(module);
PandasParser_CAPI *capi = PyMem_Malloc(sizeof(PandasParser_CAPI));
if (capi == NULL) {
PyErr_NoMemory();
Expand Down
33 changes: 21 additions & 12 deletions pandas/_libs/src/parser/tokenizer.c
Original file line number Diff line number Diff line change
Expand Up @@ -795,7 +795,7 @@ static int tokenize_bytes(parser_t *self, size_t line_limit,
break;
} else if (!isblank(c)) {
self->state = START_FIELD;
// fall through to subsequent state
PD_FALLTHROUGH; // fall through to subsequent state
} else {
// if whitespace char, keep slurping
break;
Expand Down Expand Up @@ -849,12 +849,12 @@ static int tokenize_bytes(parser_t *self, size_t line_limit,
self->state = WHITESPACE_LINE;
break;
}
// fall through
}

// normal character - fall through
// to handle as START_FIELD
self->state = START_FIELD;
PD_FALLTHROUGH;
}
case START_FIELD:
// expecting field
Expand Down Expand Up @@ -1130,10 +1130,10 @@ int parser_consume_rows(parser_t *self, size_t nrows) {

/* if word_deletions == 0 (i.e. this case) then char_count must
* be 0 too, as no data needs to be skipped */
const int64_t char_count = word_deletions >= 1
? (self->word_starts[word_deletions - 1] +
strlen(self->words[word_deletions - 1]) + 1)
: 0;
const uint64_t char_count =
word_deletions >= 1 ? (self->word_starts[word_deletions - 1] +
strlen(self->words[word_deletions - 1]) + 1)
: 0;

TRACE(("parser_consume_rows: Deleting %d words, %d chars\n", word_deletions,
char_count));
Expand Down Expand Up @@ -1415,9 +1415,11 @@ double xstrtod(const char *str, char **endptr, char decimal, char sci,
int negative = 0;
switch (*p) {
case '-':
negative = 1; // Fall through to increment position.
negative = 1;
PD_FALLTHROUGH; // Fall through to increment position.
case '+':
p++;
break;
}

int exponent = 0;
Expand Down Expand Up @@ -1485,9 +1487,11 @@ double xstrtod(const char *str, char **endptr, char decimal, char sci,
negative = 0;
switch (*++p) {
case '-':
negative = 1; // Fall through to increment pos.
negative = 1;
PD_FALLTHROUGH; // Fall through to increment position.
case '+':
p++;
break;
}

// Process string of digits.
Expand Down Expand Up @@ -1595,9 +1599,11 @@ double precise_xstrtod(const char *str, char **endptr, char decimal, char sci,
int negative = 0;
switch (*p) {
case '-':
negative = 1; // Fall through to increment position.
negative = 1;
PD_FALLTHROUGH; // Fall through to increment position.
case '+':
p++;
break;
}

double number = 0.;
Expand Down Expand Up @@ -1656,9 +1662,11 @@ double precise_xstrtod(const char *str, char **endptr, char decimal, char sci,
negative = 0;
switch (*++p) {
case '-':
negative = 1; // Fall through to increment pos.
negative = 1;
PD_FALLTHROUGH; // Fall through to increment position.
case '+':
p++;
break;
}

// Process string of digits.
Expand Down Expand Up @@ -1764,6 +1772,7 @@ static char *_str_copy_decimal_str_c(const char *s, char **endpos, char decimal,

double round_trip(const char *p, char **q, char decimal, char sci, char tsep,
int skip_trailing, int *error, int *maybe_int) {
UNUSED(sci);
// 'normalize' representation to C-locale; replace decimal with '.' and
// remove thousands separator.
char *endptr;
Expand Down Expand Up @@ -1975,7 +1984,7 @@ uint64_t str_to_uint64(uint_state *state, const char *p_item, int64_t int_max,
break;
}
if ((number < pre_max) ||
((number == pre_max) && (d - '0' <= dig_pre_max))) {
((number == pre_max) && ((uint64_t)(d - '0') <= dig_pre_max))) {
number = number * 10 + (d - '0');
d = *++p;

Expand All @@ -1987,7 +1996,7 @@ uint64_t str_to_uint64(uint_state *state, const char *p_item, int64_t int_max,
} else {
while (isdigit_ascii(d)) {
if ((number < pre_max) ||
((number == pre_max) && (d - '0' <= dig_pre_max))) {
((number == pre_max) && ((uint64_t)(d - '0') <= dig_pre_max))) {
number = number * 10 + (d - '0');
d = *++p;

Expand Down
12 changes: 12 additions & 0 deletions pandas/_libs/src/vendored/numpy/datetime/np_datetime_strings.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ This file implements string parsing and creation for NumPy datetime.
#include <numpy/ndarraytypes.h>
#include <numpy/npy_common.h>

#include "pandas/portable.h"
#include "pandas/vendored/numpy/datetime/np_datetime.h"
#include "pandas/vendored/numpy/datetime/np_datetime_strings.h"

Expand Down Expand Up @@ -767,27 +768,38 @@ int get_datetime_iso_8601_strlen(int local, NPY_DATETIMEUNIT base) {
/* return 4;*/
case NPY_FR_as:
len += 3; /* "###" */
PD_FALLTHROUGH;
case NPY_FR_fs:
len += 3; /* "###" */
PD_FALLTHROUGH;
case NPY_FR_ps:
len += 3; /* "###" */
PD_FALLTHROUGH;
case NPY_FR_ns:
len += 3; /* "###" */
PD_FALLTHROUGH;
case NPY_FR_us:
len += 3; /* "###" */
PD_FALLTHROUGH;
case NPY_FR_ms:
len += 4; /* ".###" */
PD_FALLTHROUGH;
case NPY_FR_s:
len += 3; /* ":##" */
PD_FALLTHROUGH;
case NPY_FR_m:
len += 3; /* ":##" */
PD_FALLTHROUGH;
case NPY_FR_h:
len += 3; /* "T##" */
PD_FALLTHROUGH;
case NPY_FR_D:
case NPY_FR_W:
len += 3; /* "-##" */
PD_FALLTHROUGH;
case NPY_FR_M:
len += 3; /* "-##" */
PD_FALLTHROUGH;
case NPY_FR_Y:
len += 21; /* 64-bit year */
break;
Expand Down
3 changes: 3 additions & 0 deletions pandas/_libs/src/vendored/ujson/lib/ultrajsonenc.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ Numeric decoder derived from TCL library

// Licence at LICENSES/ULTRAJSON_LICENSE

#include "pandas/portable.h"
#include "pandas/vendored/ujson/lib/ultrajson.h"
#include <locale.h>
#include <math.h>
Expand Down Expand Up @@ -461,6 +462,7 @@ int Buffer_EscapeStringUnvalidated(JSONObjectEncoder *enc, const char *io,
{
if (enc->encodeHTMLChars) {
// Fall through to \u00XX case below.
PD_FALLTHROUGH;
} else {
// Same as default case below.
(*of++) = (*io);
Expand Down Expand Up @@ -645,6 +647,7 @@ int Buffer_EscapeStringValidated(JSOBJ obj, JSONObjectEncoder *enc,
case 29: {
if (enc->encodeHTMLChars) {
// Fall through to \u00XX case 30 below.
PD_FALLTHROUGH;
} else {
// Same as case 1 above.
*(of++) = (*io++);
Expand Down
80 changes: 65 additions & 15 deletions pandas/_libs/src/vendored/ujson/python/JSONtoObj.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ Numeric decoder derived from TCL library
#define PY_ARRAY_UNIQUE_SYMBOL UJSON_NUMPY
#define NO_IMPORT_ARRAY
#define PY_SSIZE_T_CLEAN
#include "pandas/portable.h"
#include "pandas/vendored/ujson/lib/ultrajson.h"
#include <Python.h>
#include <numpy/arrayobject.h>
Expand Down Expand Up @@ -77,61 +78,94 @@ void Npy_releaseContext(NpyArrContext *npyarr) {
}

static int Object_objectAddKey(void *prv, JSOBJ obj, JSOBJ name, JSOBJ value) {
UNUSED(prv);
int ret = PyDict_SetItem(obj, name, value);
Py_DECREF((PyObject *)name);
Py_DECREF((PyObject *)value);
return ret == 0 ? 1 : 0;
}

static int Object_arrayAddItem(void *prv, JSOBJ obj, JSOBJ value) {
UNUSED(prv);
int ret = PyList_Append(obj, value);
Py_DECREF((PyObject *)value);
return ret == 0 ? 1 : 0;
}

static JSOBJ Object_newString(void *prv, wchar_t *start, wchar_t *end) {
UNUSED(prv);
return PyUnicode_FromWideChar(start, (end - start));
}

static JSOBJ Object_newTrue(void *prv) { Py_RETURN_TRUE; }
static JSOBJ Object_newTrue(void *prv) {
UNUSED(prv);
Py_RETURN_TRUE;
}

static JSOBJ Object_newFalse(void *prv) { Py_RETURN_FALSE; }
static JSOBJ Object_newFalse(void *prv) {
UNUSED(prv);
Py_RETURN_FALSE;
}

static JSOBJ Object_newNull(void *prv) { Py_RETURN_NONE; }
static JSOBJ Object_newNull(void *prv) {
UNUSED(prv);
Py_RETURN_NONE;
}

static JSOBJ Object_newPosInf(void *prv) {
UNUSED(prv);
return PyFloat_FromDouble(Py_HUGE_VAL);
}

static JSOBJ Object_newNegInf(void *prv) {
UNUSED(prv);
return PyFloat_FromDouble(-Py_HUGE_VAL);
}

static JSOBJ Object_newObject(void *prv, void *decoder) { return PyDict_New(); }
static JSOBJ Object_newObject(void *prv, void *decoder) {
UNUSED(prv);
UNUSED(decoder);
return PyDict_New();
}

static JSOBJ Object_endObject(void *prv, JSOBJ obj) { return obj; }
static JSOBJ Object_endObject(void *prv, JSOBJ obj) {
UNUSED(prv);
return obj;
}

static JSOBJ Object_newArray(void *prv, void *decoder) { return PyList_New(0); }
static JSOBJ Object_newArray(void *prv, void *decoder) {
UNUSED(prv);
UNUSED(decoder);
return PyList_New(0);
}

static JSOBJ Object_endArray(void *prv, JSOBJ obj) { return obj; }
static JSOBJ Object_endArray(void *prv, JSOBJ obj) {
UNUSED(prv);
return obj;
}

static JSOBJ Object_newInteger(void *prv, JSINT32 value) {
return PyLong_FromLong((long)value);
UNUSED(prv);
return PyLong_FromLong(value);
}

static JSOBJ Object_newLong(void *prv, JSINT64 value) {
UNUSED(prv);
return PyLong_FromLongLong(value);
}

static JSOBJ Object_newUnsignedLong(void *prv, JSUINT64 value) {
UNUSED(prv);
return PyLong_FromUnsignedLongLong(value);
}

static JSOBJ Object_newDouble(void *prv, double value) {
UNUSED(prv);
return PyFloat_FromDouble(value);
}

static void Object_releaseObject(void *prv, JSOBJ obj, void *_decoder) {
UNUSED(prv);
PyObjectDecoder *decoder = (PyObjectDecoder *)_decoder;
if (obj != decoder->npyarr_addr) {
Py_XDECREF(((PyObject *)obj));
Expand All @@ -141,6 +175,7 @@ static void Object_releaseObject(void *prv, JSOBJ obj, void *_decoder) {
static char *g_kwlist[] = {"obj", "precise_float", "labelled", "dtype", NULL};

PyObject *JSONToObj(PyObject *self, PyObject *args, PyObject *kwargs) {
UNUSED(self);
PyObject *ret;
PyObject *sarg;
PyObject *arg;
Expand All @@ -151,13 +186,28 @@ PyObject *JSONToObj(PyObject *self, PyObject *args, PyObject *kwargs) {
int labelled = 0;

JSONObjectDecoder dec = {
Object_newString, Object_objectAddKey, Object_arrayAddItem,
Object_newTrue, Object_newFalse, Object_newNull,
Object_newPosInf, Object_newNegInf, Object_newObject,
Object_endObject, Object_newArray, Object_endArray,
Object_newInteger, Object_newLong, Object_newUnsignedLong,
Object_newDouble, Object_releaseObject, PyObject_Malloc,
PyObject_Free, PyObject_Realloc};
.newString = Object_newString,
.objectAddKey = Object_objectAddKey,
.arrayAddItem = Object_arrayAddItem,
.newTrue = Object_newTrue,
.newFalse = Object_newFalse,
.newNull = Object_newNull,
.newPosInf = Object_newPosInf,
.newNegInf = Object_newNegInf,
.newObject = Object_newObject,
.endObject = Object_endObject,
.newArray = Object_newArray,
.endArray = Object_endArray,
.newInt = Object_newInteger,
.newLong = Object_newLong,
.newUnsignedLong = Object_newUnsignedLong,
.newDouble = Object_newDouble,
.releaseObject = Object_releaseObject,
.malloc = PyObject_Malloc,
.free = PyObject_Free,
.realloc = PyObject_Realloc,
.errorStr = NULL,
};

dec.preciseFloat = 0;
dec.prv = NULL;
Expand Down
Loading