Coverage Report

Created: 2025-07-04 06:49

/src/cpython/Objects/boolobject.c
Line
Count
Source (jump to first uncovered line)
1
/* Boolean type, a subtype of int */
2
3
#include "Python.h"
4
#include "pycore_long.h"          // FALSE_TAG TRUE_TAG
5
#include "pycore_modsupport.h"    // _PyArg_NoKwnames()
6
#include "pycore_object.h"        // _Py_FatalRefcountError()
7
#include "pycore_runtime.h"       // _Py_ID()
8
9
#include <stddef.h>
10
11
/* We define bool_repr to return "False" or "True" */
12
13
static PyObject *
14
bool_repr(PyObject *self)
15
350
{
16
350
    return self == Py_True ? &_Py_ID(True) : &_Py_ID(False);
17
350
}
18
19
/* Function to return a bool from a C long */
20
21
PyObject *PyBool_FromLong(long ok)
22
157M
{
23
157M
    return ok ? Py_True : Py_False;
24
157M
}
25
26
/* We define bool_new to always return either Py_True or Py_False */
27
28
static PyObject *
29
bool_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
30
0
{
31
0
    PyObject *x = Py_False;
32
0
    long ok;
33
34
0
    if (!_PyArg_NoKeywords("bool", kwds))
35
0
        return NULL;
36
0
    if (!PyArg_UnpackTuple(args, "bool", 0, 1, &x))
37
0
        return NULL;
38
0
    ok = PyObject_IsTrue(x);
39
0
    if (ok < 0)
40
0
        return NULL;
41
0
    return PyBool_FromLong(ok);
42
0
}
43
44
static PyObject *
45
bool_vectorcall(PyObject *type, PyObject * const*args,
46
                size_t nargsf, PyObject *kwnames)
47
60
{
48
60
    long ok = 0;
49
60
    if (!_PyArg_NoKwnames("bool", kwnames)) {
50
0
        return NULL;
51
0
    }
52
53
60
    Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
54
60
    if (!_PyArg_CheckPositional("bool", nargs, 0, 1)) {
55
0
        return NULL;
56
0
    }
57
58
60
    assert(PyType_Check(type));
59
60
    if (nargs) {
60
60
        ok = PyObject_IsTrue(args[0]);
61
60
        if (ok < 0) {
62
0
            return NULL;
63
0
        }
64
60
    }
65
60
    return PyBool_FromLong(ok);
66
60
}
67
68
/* Arithmetic operations redefined to return bool if both args are bool. */
69
70
static PyObject *
71
bool_invert(PyObject *v)
72
0
{
73
0
    if (PyErr_WarnEx(PyExc_DeprecationWarning,
74
0
                     "Bitwise inversion '~' on bool is deprecated and will be removed in "
75
0
                     "Python 3.16. This returns the bitwise inversion of the underlying int "
76
0
                     "object and is usually not what you expect from negating "
77
0
                     "a bool. Use the 'not' operator for boolean negation or "
78
0
                     "~int(x) if you really want the bitwise inversion of the "
79
0
                     "underlying int.",
80
0
                     1) < 0) {
81
0
        return NULL;
82
0
    }
83
0
    return PyLong_Type.tp_as_number->nb_invert(v);
84
0
}
85
86
static PyObject *
87
bool_and(PyObject *a, PyObject *b)
88
0
{
89
0
    if (!PyBool_Check(a) || !PyBool_Check(b))
90
0
        return PyLong_Type.tp_as_number->nb_and(a, b);
91
0
    return PyBool_FromLong((a == Py_True) & (b == Py_True));
92
0
}
93
94
static PyObject *
95
bool_or(PyObject *a, PyObject *b)
96
0
{
97
0
    if (!PyBool_Check(a) || !PyBool_Check(b))
98
0
        return PyLong_Type.tp_as_number->nb_or(a, b);
99
0
    return PyBool_FromLong((a == Py_True) | (b == Py_True));
100
0
}
101
102
static PyObject *
103
bool_xor(PyObject *a, PyObject *b)
104
0
{
105
0
    if (!PyBool_Check(a) || !PyBool_Check(b))
106
0
        return PyLong_Type.tp_as_number->nb_xor(a, b);
107
0
    return PyBool_FromLong((a == Py_True) ^ (b == Py_True));
108
0
}
109
110
/* Doc string */
111
112
PyDoc_STRVAR(bool_doc,
113
"bool(object=False, /)\n\
114
--\n\
115
\n\
116
Returns True when the argument is true, False otherwise.\n\
117
The builtins True and False are the only two instances of the class bool.\n\
118
The class bool is a subclass of the class int, and cannot be subclassed.");
119
120
/* Arithmetic methods -- only so we can override &, |, ^. */
121
122
static PyNumberMethods bool_as_number = {
123
    0,                          /* nb_add */
124
    0,                          /* nb_subtract */
125
    0,                          /* nb_multiply */
126
    0,                          /* nb_remainder */
127
    0,                          /* nb_divmod */
128
    0,                          /* nb_power */
129
    0,                          /* nb_negative */
130
    0,                          /* nb_positive */
131
    0,                          /* nb_absolute */
132
    0,                          /* nb_bool */
133
    bool_invert,                /* nb_invert */
134
    0,                          /* nb_lshift */
135
    0,                          /* nb_rshift */
136
    bool_and,                   /* nb_and */
137
    bool_xor,                   /* nb_xor */
138
    bool_or,                    /* nb_or */
139
    0,                          /* nb_int */
140
    0,                          /* nb_reserved */
141
    0,                          /* nb_float */
142
    0,                          /* nb_inplace_add */
143
    0,                          /* nb_inplace_subtract */
144
    0,                          /* nb_inplace_multiply */
145
    0,                          /* nb_inplace_remainder */
146
    0,                          /* nb_inplace_power */
147
    0,                          /* nb_inplace_lshift */
148
    0,                          /* nb_inplace_rshift */
149
    0,                          /* nb_inplace_and */
150
    0,                          /* nb_inplace_xor */
151
    0,                          /* nb_inplace_or */
152
    0,                          /* nb_floor_divide */
153
    0,                          /* nb_true_divide */
154
    0,                          /* nb_inplace_floor_divide */
155
    0,                          /* nb_inplace_true_divide */
156
    0,                          /* nb_index */
157
};
158
159
static void
160
bool_dealloc(PyObject *boolean)
161
0
{
162
    /* This should never get called, but we also don't want to SEGV if
163
     * we accidentally decref Booleans out of existence. Instead,
164
     * since bools are immortal, re-set the reference count.
165
     */
166
0
    _Py_SetImmortal(boolean);
167
0
}
168
169
/* The type object for bool.  Note that this cannot be subclassed! */
170
171
PyTypeObject PyBool_Type = {
172
    PyVarObject_HEAD_INIT(&PyType_Type, 0)
173
    "bool",
174
    offsetof(struct _longobject, long_value.ob_digit),  /* tp_basicsize */
175
    sizeof(digit),                              /* tp_itemsize */
176
    bool_dealloc,                               /* tp_dealloc */
177
    0,                                          /* tp_vectorcall_offset */
178
    0,                                          /* tp_getattr */
179
    0,                                          /* tp_setattr */
180
    0,                                          /* tp_as_async */
181
    bool_repr,                                  /* tp_repr */
182
    &bool_as_number,                            /* tp_as_number */
183
    0,                                          /* tp_as_sequence */
184
    0,                                          /* tp_as_mapping */
185
    0,                                          /* tp_hash */
186
    0,                                          /* tp_call */
187
    0,                                          /* tp_str */
188
    0,                                          /* tp_getattro */
189
    0,                                          /* tp_setattro */
190
    0,                                          /* tp_as_buffer */
191
    Py_TPFLAGS_DEFAULT,                         /* tp_flags */
192
    bool_doc,                                   /* tp_doc */
193
    0,                                          /* tp_traverse */
194
    0,                                          /* tp_clear */
195
    0,                                          /* tp_richcompare */
196
    0,                                          /* tp_weaklistoffset */
197
    0,                                          /* tp_iter */
198
    0,                                          /* tp_iternext */
199
    0,                                          /* tp_methods */
200
    0,                                          /* tp_members */
201
    0,                                          /* tp_getset */
202
    &PyLong_Type,                               /* tp_base */
203
    0,                                          /* tp_dict */
204
    0,                                          /* tp_descr_get */
205
    0,                                          /* tp_descr_set */
206
    0,                                          /* tp_dictoffset */
207
    0,                                          /* tp_init */
208
    0,                                          /* tp_alloc */
209
    bool_new,                                   /* tp_new */
210
    .tp_vectorcall = bool_vectorcall,
211
};
212
213
/* The objects representing bool values False and True */
214
215
struct _longobject _Py_FalseStruct = {
216
    PyObject_HEAD_INIT(&PyBool_Type)
217
    { .lv_tag = _PyLong_FALSE_TAG,
218
        { 0 }
219
    }
220
};
221
222
struct _longobject _Py_TrueStruct = {
223
    PyObject_HEAD_INIT(&PyBool_Type)
224
    { .lv_tag = _PyLong_TRUE_TAG,
225
        { 1 }
226
    }
227
};