https://github.com/python/cpython/commit/f2fa291db832142484ba536e73df5ac16b1f66fa
commit: f2fa291db832142484ba536e73df5ac16b1f66fa
branch: main
author: Pieter Eendebak <[email protected]>
committer: markshannon <[email protected]>
date: 2026-05-21T15:54:46+01:00
summary:
gh-148871: Add CONSTANT_EMPTY_TUPLE to LOAD_COMMON_CONSTANT (GH-149688)
files:
A
Misc/NEWS.d/next/Core_and_Builtins/2026-05-11-18-20-41.gh-issue-148871.AeCbq7.rst
M Include/internal/pycore_magic_number.h
M Include/internal/pycore_opcode_utils.h
M Lib/dis.py
M Lib/opcode.py
M Lib/test/test_peepholer.py
M Python/flowgraph.c
M Python/pylifecycle.c
diff --git a/Include/internal/pycore_magic_number.h
b/Include/internal/pycore_magic_number.h
index 0f1af8ba338865..6a8fa124ba38a7 100644
--- a/Include/internal/pycore_magic_number.h
+++ b/Include/internal/pycore_magic_number.h
@@ -298,6 +298,7 @@ Known values:
Python 3.15a8 3665 (Add FOR_ITER_VIRTUAL and GET_ITER specializations)
Python 3.15b1 3666 (Add SEND_VIRTUAL and SEND_ASYNC_GEN specializations)
Python 3.16a0 3700 (Initial version)
+ Python 3.16a0 3701 (Add CONSTANT_EMPTY_TUPLE to LOAD_COMMON_CONSTANT)
Python 3.17 will start with 3750
@@ -311,7 +312,7 @@ PC/launcher.c must also be updated.
*/
-#define PYC_MAGIC_NUMBER 3700
+#define PYC_MAGIC_NUMBER 3701
/* This is equivalent to converting PYC_MAGIC_NUMBER to 2 bytes
(little-endian) and then appending b'\r\n'. */
#define PYC_MAGIC_NUMBER_TOKEN \
diff --git a/Include/internal/pycore_opcode_utils.h
b/Include/internal/pycore_opcode_utils.h
index b20718344b3998..7067b48ec22cb3 100644
--- a/Include/internal/pycore_opcode_utils.h
+++ b/Include/internal/pycore_opcode_utils.h
@@ -81,7 +81,8 @@ extern "C" {
#define CONSTANT_FALSE 10
#define CONSTANT_MINUS_ONE 11
#define CONSTANT_BUILTIN_FROZENSET 12
-#define NUM_COMMON_CONSTANTS 13
+#define CONSTANT_EMPTY_TUPLE 13
+#define NUM_COMMON_CONSTANTS 14
/* Values used in the oparg for RESUME */
#define RESUME_AT_FUNC_START 0
diff --git a/Lib/dis.py b/Lib/dis.py
index d60507ae473453..cb32a4c0c7d303 100644
--- a/Lib/dis.py
+++ b/Lib/dis.py
@@ -698,8 +698,8 @@ def _get_const_value(op, arg, co_consts):
if op == LOAD_SMALL_INT:
return arg
if op == LOAD_COMMON_CONSTANT:
- # Opargs 0-6 are callables; 7-11 are literal values.
- if 7 <= arg <= 11:
+ # Opargs 0-6 and 12 are callables; 7-11 and 13 are literal values.
+ if 7 <= arg <= 11 or arg == 13:
return _common_constants[arg]
return UNKNOWN
argval = UNKNOWN
diff --git a/Lib/opcode.py b/Lib/opcode.py
index bb7824da70e8e5..750d83b2c87af5 100644
--- a/Lib/opcode.py
+++ b/Lib/opcode.py
@@ -44,7 +44,7 @@
builtins.set,
# Append-only — must match CONSTANT_* in
# Include/internal/pycore_opcode_utils.h.
- None, "", True, False, -1, builtins.frozenset]
+ None, "", True, False, -1, builtins.frozenset, ()]
_nb_ops = _opcode.get_nb_ops()
hascompare = [opmap["COMPARE_OP"]]
diff --git a/Lib/test/test_peepholer.py b/Lib/test/test_peepholer.py
index 61c4ec9b7d5b4a..28748009f731bc 100644
--- a/Lib/test/test_peepholer.py
+++ b/Lib/test/test_peepholer.py
@@ -1307,10 +1307,10 @@ def test_build_empty_tuple(self):
('RETURN_VALUE', None, 0),
]
after = [
- ('LOAD_CONST', 0, 0),
+ ('LOAD_COMMON_CONSTANT', opcode._common_constants.index(()), 0),
('RETURN_VALUE', None, 0),
]
- self.cfg_optimization_test(before, after, consts=[],
expected_consts=[()])
+ self.cfg_optimization_test(before, after, consts=[],
expected_consts=[])
def test_fold_tuple_of_constants(self):
before = [
@@ -1365,10 +1365,10 @@ def test_fold_constant_intrinsic_list_to_tuple(self):
('RETURN_VALUE', None, 0)
]
after = [
- ('LOAD_CONST', 0, 0),
+ ('LOAD_COMMON_CONSTANT', opcode._common_constants.index(()), 0),
('RETURN_VALUE', None, 0)
]
- self.cfg_optimization_test(before, after, consts=[],
expected_consts=[()])
+ self.cfg_optimization_test(before, after, consts=[],
expected_consts=[])
# multiple BUILD_LIST 0: ([], 1, [], 2)
same = [
diff --git
a/Misc/NEWS.d/next/Core_and_Builtins/2026-05-11-18-20-41.gh-issue-148871.AeCbq7.rst
b/Misc/NEWS.d/next/Core_and_Builtins/2026-05-11-18-20-41.gh-issue-148871.AeCbq7.rst
new file mode 100644
index 00000000000000..506e369f553e50
--- /dev/null
+++
b/Misc/NEWS.d/next/Core_and_Builtins/2026-05-11-18-20-41.gh-issue-148871.AeCbq7.rst
@@ -0,0 +1,3 @@
+The empty tuple ``()`` is now loaded via :opcode:`LOAD_COMMON_CONSTANT`
+instead of :opcode:`LOAD_CONST`, removing it from per-code-object
+:attr:`~codeobject.co_consts` tuples.
diff --git a/Python/flowgraph.c b/Python/flowgraph.c
index 224426b7aa44bc..6e3e5378cfbf15 100644
--- a/Python/flowgraph.c
+++ b/Python/flowgraph.c
@@ -1468,6 +1468,10 @@ maybe_instr_make_load_common_const(cfg_instr *instr,
PyObject *newconst)
&& PyUnicode_GET_LENGTH(newconst) == 0) {
oparg = CONSTANT_EMPTY_STR;
}
+ else if (PyTuple_CheckExact(newconst)
+ && PyTuple_GET_SIZE(newconst) == 0) {
+ oparg = CONSTANT_EMPTY_TUPLE;
+ }
else if (PyLong_CheckExact(newconst)) {
int overflow;
long val = PyLong_AsLongAndOverflow(newconst, &overflow);
diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c
index bbf2ce4f5eee7d..a17c3baca3d006 100644
--- a/Python/pylifecycle.c
+++ b/Python/pylifecycle.c
@@ -893,6 +893,8 @@ pycore_init_builtins(PyThreadState *tstate)
interp->common_consts[CONSTANT_MINUS_ONE] =
(PyObject *)&_PyLong_SMALL_INTS[_PY_NSMALLNEGINTS - 1];
interp->common_consts[CONSTANT_BUILTIN_FROZENSET] = (PyObject
*)&PyFrozenSet_Type;
+ interp->common_consts[CONSTANT_EMPTY_TUPLE] =
+ Py_GetConstantBorrowed(Py_CONSTANT_EMPTY_TUPLE);
for (int i = 0; i < NUM_COMMON_CONSTANTS; i++) {
assert(interp->common_consts[i] != NULL);
}
_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]