Repository: numpy/numpy
File: numpy/_core/src/umath/ufunc_object.c (C)

Code before:
            ret = -1;  // Real error (should never happen).
        }
    }
  fail:
    Py_DECREF(dt);
    return ret;
}

/*
 * Main ufunc call implementation.
 *
 * This implementation makes use of the "fastcall" way of passing keyword
 * arguments and is called directly from `ufunc_generic_vectorcall` when
 * Python has `tp_vectorcall` (Python 3.8+).
 * If `tp_vectorcall` is not available, the dictionary `kwargs` are unpacked in
 * `ufunc_generic_call` with fairly little overhead.
 */
static PyObject *
ufunc_generic_fastcall(PyUFuncObject *ufunc,
        PyObject *const *args, Py_ssize_t len_args, PyObject *kwnames,
        npy_bool outer)
{
    int errval;
    int nin = ufunc->nin, nout = ufunc->nout, nop = ufunc->nargs;

    if (!PyArray_Check(args[0]) && nin == 1 && nout == 1
            && len_args == 1 && kwnames == NULL && !ufunc->core_enabled) {
        // Possibly scalar input, try the fast path, falling back on failure.
        PyObject *result = NULL;
        if (try_trivial_scalar_call(ufunc, args[0], &result) != -2) {
            return result;
        }
    }
    /* All following variables are cleared in the `fail` error path */
    ufunc_full_args full_args = {NULL, NULL};
    PyArrayObject *wheremask = NULL;

    /*
     * Scratch space for operands, dtypes, etc.  Note that operands and
     * operation_descrs may hold an entry for the wheremask.
     */
    NPY_ALLOC_WORKSPACE(scratch_objs, void *, UFUNC_STACK_NARGS * 4 + 2, nop * 4 + 2);
    if (scratch_objs == NULL) {
        return NULL;
    }
    memset(scratch_objs, 0, sizeof(void *) * (nop * 4 + 2));

    PyArray_DTypeMeta **signature = (PyArray_DTypeMeta **)scratch_objs;
    PyArrayObject **operands = (PyArrayObject **)(signature + nop);
    PyArray_DTypeMeta **operand_DTypes = (PyArray_DTypeMeta **)(operands + nop + 1);
    PyArray_Descr **operation_descrs = (PyArray_Descr **)(operand_DTypes + nop);

Review comment (bug):
This should be `len_args == 1 && kwnames == NULL && !PyArray_Check(args[0])` (~with no `kwnames`,~ wrong, those do matter). Will push together with other changes later.

Code after:
    }
    npy_intp n = 1;
    ret = strided_loop(&context, data, &n, strides, auxdata);
    NPY_AUXDATA_FREE(auxdata);
    if (ret == 0) {
        if (!(flags & NPY_METH_NO_FLOATINGPOINT_ERRORS)) {
            // Check for any unmasked floating point errors (note: faster
            // than _check_ufunc_fperr as one doesn't need mask up front).
            int fpe_errors = npy_get_floatstatus();
            if (fpe_errors) {
                if (PyUFunc_GiveFloatingpointErrors(
                        ufunc_get_name_cstr(ufunc), fpe_errors) < 0) {
                    ret = -1;  // Real error, falling back would not help.
                    goto bail;
                }
            }
        }
        *result = PyArray_Scalar(out, dt, NULL);
        if (*result == NULL) {
            ret = -1;  // Real error (should never happen).
        }
    }
  bail:
    Py_DECREF(dt);
    return ret;
}

/*
 * Main ufunc call implementation.
 *
 * This implementation makes use of the "fastcall" way of passing keyword
 * arguments and is called directly from `ufunc_generic_vectorcall` when
 * Python has `tp_vectorcall` (Python 3.8+).
 * If `tp_vectorcall` is not available, the dictionary `kwargs` are unpacked in
 * `ufunc_generic_call` with fairly little overhead.
 */
static PyObject *
ufunc_generic_fastcall(PyUFuncObject *ufunc,
        PyObject *const *args, Py_ssize_t len_args, PyObject *kwnames,
        npy_bool outer)
{
    int errval;
    int nin = ufunc->nin, nout = ufunc->nout, nop = ufunc->nargs;

    if (len_args == 1 && kwnames == NULL && !PyArray_Check(args[0])
            && nin == 1 && nout == 1 && !ufunc->core_enabled) {
        // Possibly scalar input, try the fast path, falling back on failure.
        PyObject *result = NULL;
        if (try_trivial_scalar_call(ufunc, args[0], &result) != -2) {
            return result;
        }