Python-checkins
Threads by month
- ----- 2024 -----
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2004 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2003 -----
- December
- November
- October
- September
- August
March 2022
- 1 participants
- 509 discussions
bpo-47120: Replace the JUMP_ABSOLUTE opcode by the relative JUMP_BACKWARD (GH-32115)
by markshannon 31 Mar '22
by markshannon 31 Mar '22
31 Mar '22
https://github.com/python/cpython/commit/a00518d9ad9a8f408a9699191019d75dd8…
commit: a00518d9ad9a8f408a9699191019d75dd8406c32
branch: main
author: Irit Katriel <1055913+iritkatriel(a)users.noreply.github.com>
committer: markshannon <mark(a)hotpy.org>
date: 2022-03-31T14:14:15+01:00
summary:
bpo-47120: Replace the JUMP_ABSOLUTE opcode by the relative JUMP_BACKWARD (GH-32115)
files:
A Misc/NEWS.d/next/Core and Builtins/2022-03-25-21-51-10.bpo-47120.9YJ-Xw.rst
M Doc/library/dis.rst
M Doc/whatsnew/3.11.rst
M Include/opcode.h
M Lib/dis.py
M Lib/importlib/_bootstrap_external.py
M Lib/opcode.py
M Lib/test/test_dis.py
M Lib/test/test_peepholer.py
M Objects/frameobject.c
M Programs/test_frozenmain.h
M Python/ceval.c
M Python/compile.c
M Python/opcode_targets.h
M Python/specialize.c
diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst
index 877e11b7376b7..d1a0cecd82841 100644
--- a/Doc/library/dis.rst
+++ b/Doc/library/dis.rst
@@ -895,6 +895,13 @@ iterations of the loop.
Increments bytecode counter by *delta*.
+.. opcode:: JUMP_BACKWARD (delta)
+
+ Decrements bytecode counter by *delta*.
+
+ .. versionadded:: 3.11
+
+
.. opcode:: POP_JUMP_IF_TRUE (target)
If TOS is true, sets the bytecode counter to *target*. TOS is popped.
@@ -974,11 +981,6 @@ iterations of the loop.
.. versionadded:: 3.1
-.. opcode:: JUMP_ABSOLUTE (target)
-
- Set bytecode counter to *target*.
-
-
.. opcode:: JUMP_NO_INTERRUPT (target)
Set bytecode counter to *target*. Do not check for interrupts.
diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst
index 129e87ebafc2a..1bd958724f3be 100644
--- a/Doc/whatsnew/3.11.rst
+++ b/Doc/whatsnew/3.11.rst
@@ -522,6 +522,7 @@ CPython bytecode changes
* :opcode:`JUMP_IF_NOT_EXC_MATCH` no longer pops the active exception.
+* Replaced :opcode:`JUMP_ABSOLUTE` by the relative :opcode:`JUMP_BACKWARD`.
Deprecated
==========
diff --git a/Include/opcode.h b/Include/opcode.h
index 0ce7c158bbd58..3a7db438ede1f 100644
--- a/Include/opcode.h
+++ b/Include/opcode.h
@@ -67,7 +67,6 @@ extern "C" {
#define JUMP_FORWARD 110
#define JUMP_IF_FALSE_OR_POP 111
#define JUMP_IF_TRUE_OR_POP 112
-#define JUMP_ABSOLUTE 113
#define POP_JUMP_IF_FALSE 114
#define POP_JUMP_IF_TRUE 115
#define LOAD_GLOBAL 116
@@ -94,6 +93,7 @@ extern "C" {
#define LOAD_DEREF 137
#define STORE_DEREF 138
#define DELETE_DEREF 139
+#define JUMP_BACKWARD 140
#define CALL_FUNCTION_EX 142
#define EXTENDED_ARG 144
#define LIST_APPEND 145
@@ -135,7 +135,7 @@ extern "C" {
#define COMPARE_OP_FLOAT_JUMP 27
#define COMPARE_OP_INT_JUMP 28
#define COMPARE_OP_STR_JUMP 29
-#define JUMP_ABSOLUTE_QUICK 34
+#define JUMP_BACKWARD_QUICK 34
#define LOAD_ATTR_ADAPTIVE 36
#define LOAD_ATTR_INSTANCE_VALUE 37
#define LOAD_ATTR_MODULE 38
@@ -168,7 +168,7 @@ extern "C" {
#define PRECALL_NO_KW_METHOD_DESCRIPTOR_O 79
#define PRECALL_NO_KW_STR_1 80
#define PRECALL_NO_KW_TUPLE_1 81
-#define PRECALL_NO_KW_TYPE_1 140
+#define PRECALL_NO_KW_TYPE_1 113
#define PRECALL_PYFUNC 141
#define RESUME_QUICK 143
#define STORE_ATTR_ADAPTIVE 150
@@ -196,7 +196,7 @@ static const uint32_t _PyOpcode_RelativeJump[8] = {
0U,
536870912U,
134234112U,
- 0U,
+ 4096U,
0U,
0U,
0U,
@@ -205,8 +205,8 @@ static const uint32_t _PyOpcode_Jump[8] = {
0U,
0U,
536870912U,
- 2316288000U,
- 67U,
+ 2316156928U,
+ 4163U,
0U,
0U,
0U,
@@ -289,8 +289,8 @@ const uint8_t _PyOpcode_Deopt[256] = {
[IMPORT_NAME] = IMPORT_NAME,
[IMPORT_STAR] = IMPORT_STAR,
[IS_OP] = IS_OP,
- [JUMP_ABSOLUTE] = JUMP_ABSOLUTE,
- [JUMP_ABSOLUTE_QUICK] = JUMP_ABSOLUTE,
+ [JUMP_BACKWARD] = JUMP_BACKWARD,
+ [JUMP_BACKWARD_QUICK] = JUMP_BACKWARD,
[JUMP_FORWARD] = JUMP_FORWARD,
[JUMP_IF_FALSE_OR_POP] = JUMP_IF_FALSE_OR_POP,
[JUMP_IF_NOT_EG_MATCH] = JUMP_IF_NOT_EG_MATCH,
diff --git a/Lib/dis.py b/Lib/dis.py
index 3b7747b03ffb1..d9936ce1a002c 100644
--- a/Lib/dis.py
+++ b/Lib/dis.py
@@ -30,6 +30,7 @@
LOAD_CONST = opmap['LOAD_CONST']
LOAD_GLOBAL = opmap['LOAD_GLOBAL']
BINARY_OP = opmap['BINARY_OP']
+JUMP_BACKWARD = opmap['JUMP_BACKWARD']
CACHE = opmap["CACHE"]
@@ -441,7 +442,8 @@ def _get_instructions_bytes(code, varname_from_oparg=None,
argval = arg*2
argrepr = "to " + repr(argval)
elif op in hasjrel:
- argval = offset + 2 + arg*2
+ signed_arg = -arg if op == JUMP_BACKWARD else arg
+ argval = offset + 2 + signed_arg*2
argrepr = "to " + repr(argval)
elif op in haslocal or op in hasfree:
argval, argrepr = _get_name_info(arg, varname_from_oparg)
@@ -566,6 +568,8 @@ def findlabels(code):
for offset, op, arg in _unpack_opargs(code):
if arg is not None:
if op in hasjrel:
+ if op == JUMP_BACKWARD:
+ arg = -arg
label = offset + 2 + arg*2
elif op in hasjabs:
label = arg*2
diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py
index 48b55bb821f8b..744fefd5e21e7 100644
--- a/Lib/importlib/_bootstrap_external.py
+++ b/Lib/importlib/_bootstrap_external.py
@@ -396,6 +396,7 @@ def _write_atomic(path, data, mode=0o666):
# Python 3.11a6 3486 (Use inline caching for PRECALL and CALL)
# Python 3.11a6 3487 (Remove the adaptive "oparg counter" mechanism)
# Python 3.11a6 3488 (LOAD_GLOBAL can push additional NULL)
+# Python 3.11a6 3489 (Add JUMP_BACKWARD, remove JUMP_ABSOLUTE)
# Python 3.12 will start with magic number 3500
@@ -410,7 +411,7 @@ def _write_atomic(path, data, mode=0o666):
# Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array
# in PC/launcher.c must also be updated.
-MAGIC_NUMBER = (3488).to_bytes(2, 'little') + b'\r\n'
+MAGIC_NUMBER = (3489).to_bytes(2, 'little') + b'\r\n'
_RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c
_PYCACHE = '__pycache__'
diff --git a/Lib/opcode.py b/Lib/opcode.py
index 0b463d3f183aa..6bc64177ac8fc 100644
--- a/Lib/opcode.py
+++ b/Lib/opcode.py
@@ -128,10 +128,9 @@ def jabs_op(name, op, entries=0):
hascompare.append(107)
name_op('IMPORT_NAME', 108) # Index in name list
name_op('IMPORT_FROM', 109) # Index in name list
-jrel_op('JUMP_FORWARD', 110) # Number of bytes to skip
+jrel_op('JUMP_FORWARD', 110) # Number of words to skip
jabs_op('JUMP_IF_FALSE_OR_POP', 111) # Target byte offset from beginning of code
jabs_op('JUMP_IF_TRUE_OR_POP', 112) # ""
-jabs_op('JUMP_ABSOLUTE', 113) # ""
jabs_op('POP_JUMP_IF_FALSE', 114) # ""
jabs_op('POP_JUMP_IF_TRUE', 115) # ""
name_op('LOAD_GLOBAL', 116, 5) # Index in name list
@@ -166,6 +165,7 @@ def jabs_op(name, op, entries=0):
hasfree.append(138)
def_op('DELETE_DEREF', 139)
hasfree.append(139)
+jrel_op('JUMP_BACKWARD', 140) # Number of words to skip (backwards)
def_op('CALL_FUNCTION_EX', 142) # Flags
@@ -259,8 +259,8 @@ def jabs_op(name, op, entries=0):
"COMPARE_OP_INT_JUMP",
"COMPARE_OP_STR_JUMP",
],
- "JUMP_ABSOLUTE": [
- "JUMP_ABSOLUTE_QUICK",
+ "JUMP_BACKWARD": [
+ "JUMP_BACKWARD_QUICK",
],
"LOAD_ATTR": [
"LOAD_ATTR_ADAPTIVE",
diff --git a/Lib/test/test_dis.py b/Lib/test/test_dis.py
index 16bfee188e046..99db8ba0ac3b9 100644
--- a/Lib/test/test_dis.py
+++ b/Lib/test/test_dis.py
@@ -149,7 +149,7 @@ def bug708901():
>> FOR_ITER 2 (to 40)
STORE_FAST 0 (res)
-%3d JUMP_ABSOLUTE 17 (to 34)
+%3d JUMP_BACKWARD 3 (to 34)
%3d >> LOAD_CONST 0 (None)
RETURN_VALUE
@@ -354,7 +354,7 @@ def bug42562():
BINARY_OP 13 (+=)
STORE_NAME 0 (x)
- 2 JUMP_ABSOLUTE 4 (to 8)
+ 2 JUMP_BACKWARD 6 (to 8)
"""
dis_traceback = """\
@@ -574,7 +574,7 @@ def foo(x):
LOAD_FAST 1 (z)
BINARY_OP 0 (+)
LIST_APPEND 2
- JUMP_ABSOLUTE 4 (to 8)
+ JUMP_BACKWARD 8 (to 8)
>> RETURN_VALUE
""" % (dis_nested_1,
__file__,
@@ -1227,14 +1227,14 @@ def _prepare_test_cases():
Instruction(opname='LOAD_CONST', opcode=100, arg=2, argval=4, argrepr='4', offset=68, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='COMPARE_OP', opcode=107, arg=0, argval='<', argrepr='<', offset=70, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=40, argval=80, argrepr='to 80', offset=76, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='JUMP_ABSOLUTE', opcode=113, arg=16, argval=32, argrepr='to 32', offset=78, starts_line=6, is_jump_target=False, positions=None),
+ Instruction(opname='JUMP_BACKWARD', opcode=140, arg=24, argval=32, argrepr='to 32', offset=78, starts_line=6, is_jump_target=False, positions=None),
Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=80, starts_line=7, is_jump_target=True, positions=None),
Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=6, argrepr='6', offset=82, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='COMPARE_OP', opcode=107, arg=4, argval='>', argrepr='>', offset=84, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=48, argval=96, argrepr='to 96', offset=90, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=92, starts_line=8, is_jump_target=False, positions=None),
Instruction(opname='JUMP_FORWARD', opcode=110, arg=16, argval=128, argrepr='to 128', offset=94, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='JUMP_ABSOLUTE', opcode=113, arg=16, argval=32, argrepr='to 32', offset=96, starts_line=7, is_jump_target=True, positions=None),
+ Instruction(opname='JUMP_BACKWARD', opcode=140, arg=33, argval=32, argrepr='to 32', offset=96, starts_line=7, is_jump_target=True, positions=None),
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=98, starts_line=10, is_jump_target=True, positions=None),
Instruction(opname='LOAD_CONST', opcode=100, arg=4, argval='I can haz else clause?', argrepr="'I can haz else clause?'", offset=110, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=112, starts_line=None, is_jump_target=False, positions=None),
@@ -1255,7 +1255,7 @@ def _prepare_test_cases():
Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=6, argrepr='6', offset=174, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='COMPARE_OP', opcode=107, arg=4, argval='>', argrepr='>', offset=176, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=93, argval=186, argrepr='to 186', offset=182, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='JUMP_ABSOLUTE', opcode=113, arg=64, argval=128, argrepr='to 128', offset=184, starts_line=15, is_jump_target=False, positions=None),
+ Instruction(opname='JUMP_BACKWARD', opcode=140, arg=29, argval=128, argrepr='to 128', offset=184, starts_line=15, is_jump_target=False, positions=None),
Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=186, starts_line=16, is_jump_target=True, positions=None),
Instruction(opname='LOAD_CONST', opcode=100, arg=2, argval=4, argrepr='4', offset=188, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='COMPARE_OP', opcode=107, arg=0, argval='<', argrepr='<', offset=190, starts_line=None, is_jump_target=False, positions=None),
diff --git a/Lib/test/test_peepholer.py b/Lib/test/test_peepholer.py
index 6f24b291b00b5..ab715e2e8f6cb 100644
--- a/Lib/test/test_peepholer.py
+++ b/Lib/test/test_peepholer.py
@@ -127,7 +127,7 @@ def f():
return list
for elem in ('LOAD_CONST', 'POP_JUMP_IF_FALSE'):
self.assertNotInBytecode(f, elem)
- for elem in ('JUMP_ABSOLUTE',):
+ for elem in ('JUMP_BACKWARD',):
self.assertInBytecode(f, elem)
self.check_lnotab(f)
diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-03-25-21-51-10.bpo-47120.9YJ-Xw.rst b/Misc/NEWS.d/next/Core and Builtins/2022-03-25-21-51-10.bpo-47120.9YJ-Xw.rst
new file mode 100644
index 0000000000000..65208c73543d3
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2022-03-25-21-51-10.bpo-47120.9YJ-Xw.rst
@@ -0,0 +1,2 @@
+Replaced :opcode:`JUMP_ABSOLUTE` by the relative jump :opcode:`JUMP_BACKWARD`.
+
diff --git a/Objects/frameobject.c b/Objects/frameobject.c
index 13dfbf6b9db41..d49931048a625 100644
--- a/Objects/frameobject.c
+++ b/Objects/frameobject.c
@@ -237,7 +237,6 @@ mark_stacks(PyCodeObject *code_obj, int len)
stacks[i+1] = next_stack;
break;
}
- case JUMP_ABSOLUTE:
case JUMP_NO_INTERRUPT:
j = get_arg(code, i);
assert(j < len);
@@ -264,6 +263,12 @@ mark_stacks(PyCodeObject *code_obj, int len)
assert(stacks[j] == UNINITIALIZED || stacks[j] == next_stack);
stacks[j] = next_stack;
break;
+ case JUMP_BACKWARD:
+ j = i + 1 - get_arg(code, i);
+ assert(j >= 0);
+ assert(stacks[j] == UNINITIALIZED || stacks[j] == next_stack);
+ stacks[j] = next_stack;
+ break;
case GET_ITER:
case GET_AITER:
next_stack = push_value(pop_value(next_stack), Iterator);
diff --git a/Programs/test_frozenmain.h b/Programs/test_frozenmain.h
index 8cae77a4899f1..a3c09529116cc 100644
--- a/Programs/test_frozenmain.h
+++ b/Programs/test_frozenmain.h
@@ -12,7 +12,7 @@ unsigned char M_test_frozenmain[] = {
68,0,93,25,90,6,2,0,101,2,100,6,101,6,155,0,
100,7,101,5,101,6,25,0,0,0,0,0,0,0,0,0,
155,0,157,4,166,1,0,0,171,1,0,0,0,0,0,0,
- 0,0,1,0,113,60,100,1,83,0,41,8,233,0,0,0,
+ 0,0,1,0,140,26,100,1,83,0,41,8,233,0,0,0,
0,78,122,18,70,114,111,122,101,110,32,72,101,108,108,111,
32,87,111,114,108,100,122,8,115,121,115,46,97,114,103,118,
218,6,99,111,110,102,105,103,41,5,90,12,112,114,111,103,
diff --git a/Python/ceval.c b/Python/ceval.c
index a7b377724bb54..8f73ea1c01ac5 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -2218,7 +2218,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
Py_DECREF(v);
if (err != 0)
goto error;
- PREDICT(JUMP_ABSOLUTE);
+ PREDICT(JUMP_BACKWARD_QUICK);
DISPATCH();
}
@@ -2230,7 +2230,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
Py_DECREF(v);
if (err != 0)
goto error;
- PREDICT(JUMP_ABSOLUTE);
+ PREDICT(JUMP_BACKWARD_QUICK);
DISPATCH();
}
@@ -3396,7 +3396,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
if (_PyDict_SetItem_Take2((PyDictObject *)map, key, value) != 0) {
goto error;
}
- PREDICT(JUMP_ABSOLUTE);
+ PREDICT(JUMP_BACKWARD_QUICK);
DISPATCH();
}
@@ -3926,6 +3926,11 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
DISPATCH();
}
+ TARGET(JUMP_BACKWARD) {
+ _PyCode_Warmup(frame->f_code);
+ JUMP_TO_INSTRUCTION(JUMP_BACKWARD_QUICK);
+ }
+
TARGET(POP_JUMP_IF_FALSE) {
PREDICTED(POP_JUMP_IF_FALSE);
PyObject *cond = POP();
@@ -4053,12 +4058,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
DISPATCH();
}
- TARGET(JUMP_ABSOLUTE) {
- PREDICTED(JUMP_ABSOLUTE);
- _PyCode_Warmup(frame->f_code);
- JUMP_TO_INSTRUCTION(JUMP_ABSOLUTE_QUICK);
- }
-
TARGET(JUMP_NO_INTERRUPT) {
/* This bytecode is used in the `yield from` or `await` loop.
* If there is an interrupt, we want it handled in the innermost
@@ -4069,10 +4068,10 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
DISPATCH();
}
- TARGET(JUMP_ABSOLUTE_QUICK) {
- PREDICTED(JUMP_ABSOLUTE_QUICK);
+ TARGET(JUMP_BACKWARD_QUICK) {
+ PREDICTED(JUMP_BACKWARD_QUICK);
assert(oparg < INSTR_OFFSET());
- JUMPTO(oparg);
+ JUMPBY(-oparg);
CHECK_EVAL_BREAKER();
DISPATCH();
}
diff --git a/Python/compile.c b/Python/compile.c
index 06edcf1810e64..7a073777ee1cf 100644
--- a/Python/compile.c
+++ b/Python/compile.c
@@ -76,6 +76,7 @@
#define SETUP_CLEANUP 254
#define SETUP_WITH 253
#define POP_BLOCK 252
+#define JUMP 251
#define IS_TOP_LEVEL_AWAIT(c) ( \
(c->c_flags->cf_flags & PyCF_ALLOW_TOP_LEVEL_AWAIT) \
@@ -127,7 +128,9 @@ is_relative_jump(struct instr *i)
static inline int
is_jump(struct instr *i)
{
- return i->i_opcode >= SETUP_WITH || is_bit_set_in_table(_PyOpcode_Jump, i->i_opcode);
+ return i->i_opcode >= SETUP_WITH ||
+ i->i_opcode == JUMP ||
+ is_bit_set_in_table(_PyOpcode_Jump, i->i_opcode);
}
static int
@@ -985,7 +988,8 @@ stack_effect(int opcode, int oparg, int jump)
/* Jumps */
case JUMP_FORWARD:
- case JUMP_ABSOLUTE:
+ case JUMP_BACKWARD:
+ case JUMP:
case JUMP_NO_INTERRUPT:
return 0;
@@ -2839,7 +2843,7 @@ compiler_jump_if(struct compiler *c, expr_ty e, basicblock *next, int cond)
return 0;
if (!compiler_jump_if(c, e->v.IfExp.body, next, cond))
return 0;
- ADDOP_JUMP_NOLINE(c, JUMP_FORWARD, end);
+ ADDOP_JUMP_NOLINE(c, JUMP, end);
compiler_use_next_block(c, next2);
if (!compiler_jump_if(c, e->v.IfExp.orelse, next, cond))
return 0;
@@ -2870,11 +2874,11 @@ compiler_jump_if(struct compiler *c, expr_ty e, basicblock *next, int cond)
basicblock *end = compiler_new_block(c);
if (end == NULL)
return 0;
- ADDOP_JUMP_NOLINE(c, JUMP_FORWARD, end);
+ ADDOP_JUMP_NOLINE(c, JUMP, end);
compiler_use_next_block(c, cleanup);
ADDOP(c, POP_TOP);
if (!cond) {
- ADDOP_JUMP_NOLINE(c, JUMP_FORWARD, next);
+ ADDOP_JUMP_NOLINE(c, JUMP, next);
}
compiler_use_next_block(c, end);
return 1;
@@ -2908,7 +2912,7 @@ compiler_ifexp(struct compiler *c, expr_ty e)
if (!compiler_jump_if(c, e->v.IfExp.test, next, 0))
return 0;
VISIT(c, expr, e->v.IfExp.body);
- ADDOP_JUMP_NOLINE(c, JUMP_FORWARD, end);
+ ADDOP_JUMP_NOLINE(c, JUMP, end);
compiler_use_next_block(c, next);
VISIT(c, expr, e->v.IfExp.orelse);
compiler_use_next_block(c, end);
@@ -2995,7 +2999,7 @@ compiler_if(struct compiler *c, stmt_ty s)
}
VISIT_SEQ(c, stmt, s->v.If.body);
if (asdl_seq_LEN(s->v.If.orelse)) {
- ADDOP_JUMP_NOLINE(c, JUMP_FORWARD, end);
+ ADDOP_JUMP_NOLINE(c, JUMP, end);
compiler_use_next_block(c, next);
VISIT_SEQ(c, stmt, s->v.If.orelse);
}
@@ -3027,7 +3031,7 @@ compiler_for(struct compiler *c, stmt_ty s)
VISIT_SEQ(c, stmt, s->v.For.body);
/* Mark jump as artificial */
UNSET_LOC(c);
- ADDOP_JUMP(c, JUMP_ABSOLUTE, start);
+ ADDOP_JUMP(c, JUMP, start);
compiler_use_next_block(c, cleanup);
compiler_pop_fblock(c, FOR_LOOP, start);
@@ -3072,7 +3076,7 @@ compiler_async_for(struct compiler *c, stmt_ty s)
/* Success block for __anext__ */
VISIT(c, expr, s->v.AsyncFor.target);
VISIT_SEQ(c, stmt, s->v.AsyncFor.body);
- ADDOP_JUMP(c, JUMP_ABSOLUTE, start);
+ ADDOP_JUMP(c, JUMP, start);
compiler_pop_fblock(c, FOR_LOOP, start);
@@ -3184,7 +3188,7 @@ compiler_break(struct compiler *c)
if (!compiler_unwind_fblock(c, loop, 0)) {
return 0;
}
- ADDOP_JUMP(c, JUMP_ABSOLUTE, loop->fb_exit);
+ ADDOP_JUMP(c, JUMP, loop->fb_exit);
return 1;
}
@@ -3200,7 +3204,7 @@ compiler_continue(struct compiler *c)
if (loop == NULL) {
return compiler_error(c, "'continue' not properly in loop");
}
- ADDOP_JUMP(c, JUMP_ABSOLUTE, loop->fb_block);
+ ADDOP_JUMP(c, JUMP, loop->fb_block);
return 1;
}
@@ -3261,7 +3265,7 @@ compiler_try_finally(struct compiler *c, stmt_ty s)
ADDOP_NOLINE(c, POP_BLOCK);
compiler_pop_fblock(c, FINALLY_TRY, body);
VISIT_SEQ(c, stmt, s->v.Try.finalbody);
- ADDOP_JUMP_NOLINE(c, JUMP_FORWARD, exit);
+ ADDOP_JUMP_NOLINE(c, JUMP, exit);
/* `finally` block */
compiler_use_next_block(c, end);
@@ -3315,7 +3319,7 @@ compiler_try_star_finally(struct compiler *c, stmt_ty s)
ADDOP_NOLINE(c, POP_BLOCK);
compiler_pop_fblock(c, FINALLY_TRY, body);
VISIT_SEQ(c, stmt, s->v.TryStar.finalbody);
- ADDOP_JUMP_NOLINE(c, JUMP_FORWARD, exit);
+ ADDOP_JUMP_NOLINE(c, JUMP, exit);
/* `finally` block */
compiler_use_next_block(c, end);
@@ -3345,13 +3349,13 @@ compiler_try_star_finally(struct compiler *c, stmt_ty s)
[] SETUP_FINALLY L1
[] <code for S>
[] POP_BLOCK
- [] JUMP_FORWARD L0
+ [] JUMP L0
[exc] L1: <evaluate E1> )
[exc, E1] JUMP_IF_NOT_EXC_MATCH L2 ) only if E1
[exc] <assign to V1> (or POP if no V1)
[] <code for S1>
- JUMP_FORWARD L0
+ JUMP L0
[exc] L2: <evaluate E2>
.............................etc.......................
@@ -3384,7 +3388,7 @@ compiler_try_except(struct compiler *c, stmt_ty s)
if (s->v.Try.orelse && asdl_seq_LEN(s->v.Try.orelse)) {
VISIT_SEQ(c, stmt, s->v.Try.orelse);
}
- ADDOP_JUMP_NOLINE(c, JUMP_FORWARD, end);
+ ADDOP_JUMP_NOLINE(c, JUMP, end);
n = asdl_seq_LEN(s->v.Try.handlers);
compiler_use_next_block(c, except);
@@ -3447,7 +3451,7 @@ compiler_try_except(struct compiler *c, stmt_ty s)
ADDOP_LOAD_CONST(c, Py_None);
compiler_nameop(c, handler->v.ExceptHandler.name, Store);
compiler_nameop(c, handler->v.ExceptHandler.name, Del);
- ADDOP_JUMP(c, JUMP_FORWARD, end);
+ ADDOP_JUMP(c, JUMP, end);
/* except: */
compiler_use_next_block(c, cleanup_end);
@@ -3477,7 +3481,7 @@ compiler_try_except(struct compiler *c, stmt_ty s)
UNSET_LOC(c);
ADDOP(c, POP_BLOCK);
ADDOP(c, POP_EXCEPT);
- ADDOP_JUMP(c, JUMP_FORWARD, end);
+ ADDOP_JUMP(c, JUMP, end);
}
compiler_use_next_block(c, except);
}
@@ -3501,7 +3505,7 @@ compiler_try_except(struct compiler *c, stmt_ty s)
[] SETUP_FINALLY L1
[] <code for S>
[] POP_BLOCK
- [] JUMP_FORWARD L0
+ [] JUMP L0
[exc] L1: COPY 1 ) save copy of the original exception
[orig, exc] BUILD_LIST ) list for raised/reraised excs ("result")
@@ -3514,7 +3518,7 @@ compiler_try_except(struct compiler *c, stmt_ty s)
[orig, res, rest] SETUP_FINALLY R1
[orig, res, rest] <code for S1>
- [orig, res, rest] JUMP_FORWARD L2
+ [orig, res, rest] JUMP L2
[orig, res, rest, i, v] R1: LIST_APPEND 3 ) exc raised in except* body - add to res
[orig, res, rest, i] POP
@@ -3528,7 +3532,7 @@ compiler_try_except(struct compiler *c, stmt_ty s)
[exc] COPY 1
[exc, exc] POP_JUMP_IF_NOT_NONE RER
[exc] POP_TOP
- [] JUMP_FORWARD L0
+ [] JUMP L0
[exc] RER: SWAP 2
[exc, prev_exc_info] POP_EXCEPT
@@ -3572,7 +3576,7 @@ compiler_try_star_except(struct compiler *c, stmt_ty s)
VISIT_SEQ(c, stmt, s->v.TryStar.body);
compiler_pop_fblock(c, TRY_EXCEPT, body);
ADDOP_NOLINE(c, POP_BLOCK);
- ADDOP_JUMP_NOLINE(c, JUMP_FORWARD, orelse);
+ ADDOP_JUMP_NOLINE(c, JUMP, orelse);
Py_ssize_t n = asdl_seq_LEN(s->v.TryStar.handlers);
compiler_use_next_block(c, except);
@@ -3657,7 +3661,7 @@ compiler_try_star_except(struct compiler *c, stmt_ty s)
compiler_nameop(c, handler->v.ExceptHandler.name, Store);
compiler_nameop(c, handler->v.ExceptHandler.name, Del);
}
- ADDOP_JUMP(c, JUMP_FORWARD, except);
+ ADDOP_JUMP(c, JUMP, except);
/* except: */
compiler_use_next_block(c, cleanup_end);
@@ -3675,13 +3679,13 @@ compiler_try_star_except(struct compiler *c, stmt_ty s)
ADDOP_I(c, LIST_APPEND, 3); // exc
ADDOP(c, POP_TOP); // lasti
- ADDOP_JUMP(c, JUMP_ABSOLUTE, except);
+ ADDOP_JUMP(c, JUMP, except);
compiler_use_next_block(c, except);
if (i == n - 1) {
/* Add exc to the list (if not None it's the unhandled part of the EG) */
ADDOP_I(c, LIST_APPEND, 1);
- ADDOP_JUMP(c, JUMP_FORWARD, reraise_star);
+ ADDOP_JUMP(c, JUMP, reraise_star);
}
}
/* Mark as artificial */
@@ -3701,7 +3705,7 @@ compiler_try_star_except(struct compiler *c, stmt_ty s)
ADDOP(c, POP_TOP);
ADDOP(c, POP_BLOCK);
ADDOP(c, POP_EXCEPT);
- ADDOP_JUMP(c, JUMP_FORWARD, end);
+ ADDOP_JUMP(c, JUMP, end);
compiler_use_next_block(c, reraise);
ADDOP(c, POP_BLOCK);
ADDOP_I(c, SWAP, 2);
@@ -4542,7 +4546,7 @@ compiler_compare(struct compiler *c, expr_ty e)
basicblock *end = compiler_new_block(c);
if (end == NULL)
return 0;
- ADDOP_JUMP_NOLINE(c, JUMP_FORWARD, end);
+ ADDOP_JUMP_NOLINE(c, JUMP, end);
compiler_use_next_block(c, cleanup);
ADDOP_I(c, SWAP, 2);
ADDOP(c, POP_TOP);
@@ -5172,7 +5176,7 @@ compiler_sync_comprehension_generator(struct compiler *c,
}
compiler_use_next_block(c, if_cleanup);
if (start) {
- ADDOP_JUMP(c, JUMP_ABSOLUTE, start);
+ ADDOP_JUMP(c, JUMP, start);
compiler_use_next_block(c, anchor);
}
@@ -5266,7 +5270,7 @@ compiler_async_comprehension_generator(struct compiler *c,
}
}
compiler_use_next_block(c, if_cleanup);
- ADDOP_JUMP(c, JUMP_ABSOLUTE, start);
+ ADDOP_JUMP(c, JUMP, start);
compiler_pop_fblock(c, ASYNC_COMPREHENSION_GENERATOR, start);
@@ -5542,7 +5546,7 @@ compiler_async_with(struct compiler *c, stmt_ty s, int pos)
ADDOP(c, POP_TOP);
- ADDOP_JUMP(c, JUMP_ABSOLUTE, exit);
+ ADDOP_JUMP(c, JUMP, exit);
/* For exceptional outcome: */
compiler_use_next_block(c, final);
@@ -5571,7 +5575,7 @@ compiler_async_with(struct compiler *c, stmt_ty s, int pos)
<code for BLOCK>
LOAD_CONST (None, None, None)
CALL_FUNCTION_EX 0
- JUMP_FORWARD EXIT
+ JUMP EXIT
E: WITH_EXCEPT_START (calls EXPR.__exit__)
POP_JUMP_IF_TRUE T:
RERAISE
@@ -5638,7 +5642,7 @@ compiler_with(struct compiler *c, stmt_ty s, int pos)
if (!compiler_call_exit_with_nones(c))
return 0;
ADDOP(c, POP_TOP);
- ADDOP_JUMP(c, JUMP_FORWARD, exit);
+ ADDOP_JUMP(c, JUMP, exit);
/* For exceptional outcome: */
compiler_use_next_block(c, final);
@@ -6687,7 +6691,7 @@ compiler_pattern_or(struct compiler *c, pattern_ty p, pattern_context *pc)
}
}
assert(control);
- if (!compiler_addop_j(c, JUMP_FORWARD, end) ||
+ if (!compiler_addop_j(c, JUMP, end) ||
!emit_and_reset_fail_pop(c, pc))
{
goto error;
@@ -6699,7 +6703,7 @@ compiler_pattern_or(struct compiler *c, pattern_ty p, pattern_context *pc)
// Need to NULL this for the PyObject_Free call in the error block.
old_pc.fail_pop = NULL;
// No match. Pop the remaining copy of the subject and fail:
- if (!compiler_addop(c, POP_TOP) || !jump_to_fail_pop(c, pc, JUMP_FORWARD)) {
+ if (!compiler_addop(c, POP_TOP) || !jump_to_fail_pop(c, pc, JUMP)) {
goto error;
}
compiler_use_next_block(c, end);
@@ -6906,7 +6910,7 @@ compiler_match_inner(struct compiler *c, stmt_ty s, pattern_context *pc)
ADDOP(c, POP_TOP);
}
VISIT_SEQ(c, stmt, m->body);
- ADDOP_JUMP(c, JUMP_FORWARD, end);
+ ADDOP_JUMP(c, JUMP, end);
// If the pattern fails to match, we want the line number of the
// cleanup to be associated with the failed pattern, not the last line
// of the body
@@ -7045,9 +7049,10 @@ stackdepth(struct compiler *c)
stackdepth_push(&sp, instr->i_target, target_depth);
}
depth = new_depth;
- if (instr->i_opcode == JUMP_ABSOLUTE ||
- instr->i_opcode == JUMP_NO_INTERRUPT ||
- instr->i_opcode == JUMP_FORWARD ||
+ assert(instr->i_opcode != JUMP_FORWARD);
+ assert(instr->i_opcode != JUMP_BACKWARD);
+ if (instr->i_opcode == JUMP_NO_INTERRUPT ||
+ instr->i_opcode == JUMP ||
instr->i_opcode == RETURN_VALUE ||
instr->i_opcode == RAISE_VARARGS ||
instr->i_opcode == RERAISE)
@@ -7559,14 +7564,14 @@ normalize_jumps(struct assembler *a)
continue;
}
struct instr *last = &b->b_instr[b->b_iused-1];
- if (last->i_opcode == JUMP_ABSOLUTE) {
+ assert(last->i_opcode != JUMP_FORWARD);
+ assert(last->i_opcode != JUMP_BACKWARD);
+ if (last->i_opcode == JUMP) {
if (last->i_target->b_visited == 0) {
last->i_opcode = JUMP_FORWARD;
}
- }
- if (last->i_opcode == JUMP_FORWARD) {
- if (last->i_target->b_visited == 1) {
- last->i_opcode = JUMP_ABSOLUTE;
+ else {
+ last->i_opcode = JUMP_BACKWARD;
}
}
}
@@ -7602,7 +7607,14 @@ assemble_jump_offsets(struct assembler *a, struct compiler *c)
if (is_jump(instr)) {
instr->i_oparg = instr->i_target->b_offset;
if (is_relative_jump(instr)) {
- instr->i_oparg -= bsize;
+ if (instr->i_oparg < bsize) {
+ assert(instr->i_opcode == JUMP_BACKWARD);
+ instr->i_oparg = bsize - instr->i_oparg;
+ }
+ else {
+ assert(instr->i_opcode != JUMP_BACKWARD);
+ instr->i_oparg -= bsize;
+ }
}
if (instr_size(instr) != isize) {
extended_arg_recompile = 1;
@@ -8621,10 +8633,14 @@ optimize_basic_block(struct compiler *c, basicblock *bb, PyObject *consts)
inst->i_target = inst->i_target->b_next;
}
target = &inst->i_target->b_instr[0];
+ assert(target->i_opcode != JUMP_FORWARD);
+ assert(target->i_opcode != JUMP_BACKWARD);
}
else {
target = &nop;
}
+ assert(inst->i_opcode != JUMP_FORWARD);
+ assert(inst->i_opcode != JUMP_BACKWARD);
switch (inst->i_opcode) {
/* Remove LOAD_CONST const; conditional jump */
case LOAD_CONST:
@@ -8647,7 +8663,7 @@ optimize_basic_block(struct compiler *c, basicblock *bb, PyObject *consts)
inst->i_opcode = NOP;
jump_if_true = nextop == POP_JUMP_IF_TRUE;
if (is_true == jump_if_true) {
- bb->b_instr[i+1].i_opcode = JUMP_ABSOLUTE;
+ bb->b_instr[i+1].i_opcode = JUMP;
bb->b_nofallthrough = 1;
}
else {
@@ -8667,7 +8683,7 @@ optimize_basic_block(struct compiler *c, basicblock *bb, PyObject *consts)
}
jump_if_true = nextop == JUMP_IF_TRUE_OR_POP;
if (is_true == jump_if_true) {
- bb->b_instr[i+1].i_opcode = JUMP_ABSOLUTE;
+ bb->b_instr[i+1].i_opcode = JUMP;
bb->b_nofallthrough = 1;
}
else {
@@ -8738,8 +8754,7 @@ optimize_basic_block(struct compiler *c, basicblock *bb, PyObject *consts)
case POP_JUMP_IF_FALSE:
i -= jump_thread(inst, target, POP_JUMP_IF_FALSE);
break;
- case JUMP_ABSOLUTE:
- case JUMP_FORWARD:
+ case JUMP:
case JUMP_IF_FALSE_OR_POP:
i -= jump_thread(inst, target, JUMP_IF_FALSE_OR_POP);
break;
@@ -8761,8 +8776,7 @@ optimize_basic_block(struct compiler *c, basicblock *bb, PyObject *consts)
case POP_JUMP_IF_TRUE:
i -= jump_thread(inst, target, POP_JUMP_IF_TRUE);
break;
- case JUMP_ABSOLUTE:
- case JUMP_FORWARD:
+ case JUMP:
case JUMP_IF_TRUE_OR_POP:
i -= jump_thread(inst, target, JUMP_IF_TRUE_OR_POP);
break;
@@ -8782,36 +8796,38 @@ optimize_basic_block(struct compiler *c, basicblock *bb, PyObject *consts)
case POP_JUMP_IF_NOT_NONE:
case POP_JUMP_IF_NONE:
switch (target->i_opcode) {
- case JUMP_ABSOLUTE:
- case JUMP_FORWARD:
+ case JUMP:
i -= jump_thread(inst, target, inst->i_opcode);
}
break;
case POP_JUMP_IF_FALSE:
switch (target->i_opcode) {
- case JUMP_ABSOLUTE:
- case JUMP_FORWARD:
+ case JUMP:
i -= jump_thread(inst, target, POP_JUMP_IF_FALSE);
}
break;
case POP_JUMP_IF_TRUE:
switch (target->i_opcode) {
- case JUMP_ABSOLUTE:
- case JUMP_FORWARD:
+ case JUMP:
i -= jump_thread(inst, target, POP_JUMP_IF_TRUE);
}
break;
- case JUMP_ABSOLUTE:
- case JUMP_FORWARD:
+ case JUMP:
switch (target->i_opcode) {
- case JUMP_ABSOLUTE:
- case JUMP_FORWARD:
- i -= jump_thread(inst, target, JUMP_ABSOLUTE);
+ case JUMP:
+ i -= jump_thread(inst, target, JUMP);
}
break;
case FOR_ITER:
- if (target->i_opcode == JUMP_FORWARD) {
+ if (target->i_opcode == JUMP) {
+ /* This will not work now because the jump (at target) could
+ * be forward or backward and FOR_ITER only jumps forward. We
+ * can re-enable this if ever we implement a backward version
+ * of FOR_ITER.
+ */
+ /*
i -= jump_thread(inst, target, FOR_ITER);
+ */
}
break;
case SWAP:
@@ -8852,7 +8868,9 @@ extend_block(basicblock *bb) {
return 0;
}
struct instr *last = &bb->b_instr[bb->b_iused-1];
- if (last->i_opcode != JUMP_ABSOLUTE && last->i_opcode != JUMP_FORWARD) {
+ if (last->i_opcode != JUMP &&
+ last->i_opcode != JUMP_FORWARD &&
+ last->i_opcode != JUMP_BACKWARD) {
return 0;
}
if (last->i_target->b_exit && last->i_target->b_iused <= MAX_COPY_SIZE) {
@@ -8923,6 +8941,8 @@ normalize_basic_block(basicblock *bb) {
/* Mark blocks as exit and/or nofallthrough.
Raise SystemError if CFG is malformed. */
for (int i = 0; i < bb->b_iused; i++) {
+ assert(bb->b_instr[i].i_opcode != JUMP_FORWARD);
+ assert(bb->b_instr[i].i_opcode != JUMP_BACKWARD);
switch(bb->b_instr[i].i_opcode) {
case RETURN_VALUE:
case RAISE_VARARGS:
@@ -8930,8 +8950,7 @@ normalize_basic_block(basicblock *bb) {
bb->b_exit = 1;
bb->b_nofallthrough = 1;
break;
- case JUMP_ABSOLUTE:
- case JUMP_FORWARD:
+ case JUMP:
case JUMP_NO_INTERRUPT:
bb->b_nofallthrough = 1;
/* fall through */
@@ -9116,9 +9135,10 @@ optimize_cfg(struct compiler *c, struct assembler *a, PyObject *consts)
for (basicblock *b = a->a_entry; b != NULL; b = b->b_next) {
if (b->b_iused > 0) {
struct instr *b_last_instr = &b->b_instr[b->b_iused - 1];
- if (b_last_instr->i_opcode == JUMP_ABSOLUTE ||
- b_last_instr->i_opcode == JUMP_NO_INTERRUPT ||
- b_last_instr->i_opcode == JUMP_FORWARD) {
+ assert(b_last_instr->i_opcode != JUMP_FORWARD);
+ assert(b_last_instr->i_opcode != JUMP_BACKWARD);
+ if (b_last_instr->i_opcode == JUMP ||
+ b_last_instr->i_opcode == JUMP_NO_INTERRUPT) {
if (b_last_instr->i_target == b->b_next) {
assert(b->b_next->b_iused);
b->b_nofallthrough = 0;
diff --git a/Python/opcode_targets.h b/Python/opcode_targets.h
index dbcacee7e0205..3afaf0b029831 100644
--- a/Python/opcode_targets.h
+++ b/Python/opcode_targets.h
@@ -33,7 +33,7 @@ static void *opcode_targets[256] = {
&&TARGET_MATCH_MAPPING,
&&TARGET_MATCH_SEQUENCE,
&&TARGET_MATCH_KEYS,
- &&TARGET_JUMP_ABSOLUTE_QUICK,
+ &&TARGET_JUMP_BACKWARD_QUICK,
&&TARGET_PUSH_EXC_INFO,
&&TARGET_LOAD_ATTR_ADAPTIVE,
&&TARGET_LOAD_ATTR_INSTANCE_VALUE,
@@ -112,7 +112,7 @@ static void *opcode_targets[256] = {
&&TARGET_JUMP_FORWARD,
&&TARGET_JUMP_IF_FALSE_OR_POP,
&&TARGET_JUMP_IF_TRUE_OR_POP,
- &&TARGET_JUMP_ABSOLUTE,
+ &&TARGET_PRECALL_NO_KW_TYPE_1,
&&TARGET_POP_JUMP_IF_FALSE,
&&TARGET_POP_JUMP_IF_TRUE,
&&TARGET_LOAD_GLOBAL,
@@ -139,7 +139,7 @@ static void *opcode_targets[256] = {
&&TARGET_LOAD_DEREF,
&&TARGET_STORE_DEREF,
&&TARGET_DELETE_DEREF,
- &&TARGET_PRECALL_NO_KW_TYPE_1,
+ &&TARGET_JUMP_BACKWARD,
&&TARGET_PRECALL_PYFUNC,
&&TARGET_CALL_FUNCTION_EX,
&&TARGET_RESUME_QUICK,
diff --git a/Python/specialize.c b/Python/specialize.c
index 244318a609e66..08c69041e78b0 100644
--- a/Python/specialize.c
+++ b/Python/specialize.c
@@ -270,8 +270,8 @@ _PyCode_Quicken(PyCodeObject *code)
else {
assert(!_PyOpcode_Caches[opcode]);
switch (opcode) {
- case JUMP_ABSOLUTE:
- _Py_SET_OPCODE(instructions[i], JUMP_ABSOLUTE_QUICK);
+ case JUMP_BACKWARD:
+ _Py_SET_OPCODE(instructions[i], JUMP_BACKWARD_QUICK);
break;
case RESUME:
_Py_SET_OPCODE(instructions[i], RESUME_QUICK);
1
0
https://github.com/python/cpython/commit/b36d222110d0d6d84dc8e973ca87d976c2…
commit: b36d222110d0d6d84dc8e973ca87d976c2423f5d
branch: main
author: Erlend Egeberg Aasland <erlend.aasland(a)innova.no>
committer: miss-islington <31488909+miss-islington(a)users.noreply.github.com>
date: 2022-03-31T03:19:08-07:00
summary:
bpo-45847: Port _tkinter to PY_STDLIB_MOD (GH-31698)
- Remove ``--with-tclk-*`` options from `configure`
- Use pkg-config to detect `_tkinter` dependencies (Tcl/Tk, X11)
- Manual override via environment variables `TCLTK_CFLAGS` and `TCLTK_LIBS`
files:
M Doc/using/configure.rst
M Doc/whatsnew/3.10.rst
M Doc/whatsnew/3.11.rst
M Doc/whatsnew/3.9.rst
M Makefile.pre.in
M Modules/Setup.stdlib.in
M configure
M configure.ac
M pyconfig.h.in
M setup.py
diff --git a/Doc/using/configure.rst b/Doc/using/configure.rst
index f1c156c042353..debbee7117f58 100644
--- a/Doc/using/configure.rst
+++ b/Doc/using/configure.rst
@@ -404,14 +404,6 @@ Libraries options
.. versionadded:: 3.10
-.. cmdoption:: --with-tcltk-includes='-I...'
-
- Override search for Tcl and Tk include files.
-
-.. cmdoption:: --with-tcltk-libs='-L...'
-
- Override search for Tcl and Tk libraries.
-
.. cmdoption:: --with-libm=STRING
Override ``libm`` math library to *STRING* (default is system-dependent).
diff --git a/Doc/whatsnew/3.10.rst b/Doc/whatsnew/3.10.rst
index 905305be3176c..dd01c88d8ae66 100644
--- a/Doc/whatsnew/3.10.rst
+++ b/Doc/whatsnew/3.10.rst
@@ -2019,8 +2019,8 @@ Build Changes
* The ``configure`` script now uses the ``pkg-config`` utility, if available,
to detect the location of Tcl/Tk headers and libraries. As before, those
- locations can be explicitly specified with the :option:`--with-tcltk-includes`
- and :option:`--with-tcltk-libs` configuration options.
+ locations can be explicitly specified with the ``--with-tcltk-includes``
+ and ``--with-tcltk-libs`` configuration options.
(Contributed by Manolis Stamatogiannakis in :issue:`42603`.)
* Add :option:`--with-openssl-rpath` option to ``configure`` script. The option
diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst
index 837d8c8cbd016..129e87ebafc2a 100644
--- a/Doc/whatsnew/3.11.rst
+++ b/Doc/whatsnew/3.11.rst
@@ -770,11 +770,17 @@ Build Changes
* Build dependencies, compiler flags, and linker flags for most stdlib
extension modules are now detected by :program:`configure`. libffi, libnsl,
- libsqlite3, zlib, bzip2, liblzma, libcrypt, and uuid flags are detected by
- ``pkg-config`` (when available).
+ libsqlite3, zlib, bzip2, liblzma, libcrypt, Tcl/Tk libs, and uuid flags
+ are detected by ``pkg-config`` (when available).
(Contributed by Christian Heimes and Erlend Egeberg Aasland in
:issue:`bpo-45847`, :issue:`45747`, and :issue:`45763`.)
+ .. note::
+ Use the environment variables ``TCLTK_CFLAGS`` and ``TCLTK_LIBS`` to
+ manually specify the location of Tcl/Tk headers and libraries.
+ The :program:`configure` options ``--with-tcltk-includes`` and
+ ``--with-tcltk-libs`` have been removed.
+
* CPython now has experimental support for cross compiling to WebAssembly
platform ``wasm32-emscripten``. The effort is inspired by previous work
like Pyodide.
diff --git a/Doc/whatsnew/3.9.rst b/Doc/whatsnew/3.9.rst
index c7255b3d41765..6dee55e5a0e55 100644
--- a/Doc/whatsnew/3.9.rst
+++ b/Doc/whatsnew/3.9.rst
@@ -1249,7 +1249,7 @@ Build Changes
of macOS. If a macOS SDK is explicitly configured, by using
:option:`--enable-universalsdk` or ``-isysroot``, only the SDK itself is
searched. The default behavior can still be overridden with
- :option:`--with-tcltk-includes` and :option:`--with-tcltk-libs`.
+ ``--with-tcltk-includes`` and ``--with-tcltk-libs``.
(Contributed by Ned Deily in :issue:`34956`.)
* Python can now be built for Windows 10 ARM64.
diff --git a/Makefile.pre.in b/Makefile.pre.in
index 8d335a7e139fc..e784b43d0362d 100644
--- a/Makefile.pre.in
+++ b/Makefile.pre.in
@@ -302,10 +302,6 @@ _PYTHON_HOST_PLATFORM=@_PYTHON_HOST_PLATFORM@
BUILD_GNU_TYPE= @build@
HOST_GNU_TYPE= @host@
-# Tcl and Tk config info from --with-tcltk-includes and -libs options
-TCLTK_INCLUDES= @TCLTK_INCLUDES@
-TCLTK_LIBS= @TCLTK_LIBS@
-
# The task to run while instrumented when building the profile-opt target.
# To speed up profile generation, we don't run the full unit test suite
# by default. The default is "-m test --pgo". To run more tests, use
@@ -736,10 +732,8 @@ sharedmods: $(BUILDPYTHON) pybuilddir.txt @LIBMPDEC_INTERNAL@ @LIBEXPAT_INTERNAL
*) quiet="";; \
esac; \
echo "$(RUNSHARED) CC='$(CC)' LDSHARED='$(BLDSHARED)' OPT='$(OPT)' \
- _TCLTK_INCLUDES='$(TCLTK_INCLUDES)' _TCLTK_LIBS='$(TCLTK_LIBS)' \
$(PYTHON_FOR_BUILD) $(srcdir)/setup.py $$quiet build"; \
$(RUNSHARED) CC='$(CC)' LDSHARED='$(BLDSHARED)' OPT='$(OPT)' \
- _TCLTK_INCLUDES='$(TCLTK_INCLUDES)' _TCLTK_LIBS='$(TCLTK_LIBS)' \
$(PYTHON_FOR_BUILD) $(srcdir)/setup.py $$quiet build
diff --git a/Modules/Setup.stdlib.in b/Modules/Setup.stdlib.in
index 73f041eb2fba9..22c0b147c1b89 100644
--- a/Modules/Setup.stdlib.in
+++ b/Modules/Setup.stdlib.in
@@ -150,12 +150,11 @@
# needs -lcrypt
@MODULE__HASHLIB_TRUE@_hashlib _hashopenssl.c
-# needs -ltk, -ltcl, and sometimes -lX11
-#@MODULE__TKINTER_TRUE@_tkinter _tkinter.c tkappinit.c
-
# Linux: -luuid, BSD/AIX: libc's uuid_create()
@MODULE__UUID_TRUE@_uuid _uuidmodule.c
+@MODULE__TKINTER_TRUE@_tkinter _tkinter.c tkappinit.c
+
############################################################################
# macOS specific modules
diff --git a/configure b/configure
index 17f52996f4fd7..f261a86a28d1d 100755
--- a/configure
+++ b/configure
@@ -654,6 +654,8 @@ MODULE_BINASCII_FALSE
MODULE_BINASCII_TRUE
MODULE_ZLIB_FALSE
MODULE_ZLIB_TRUE
+MODULE__TKINTER_FALSE
+MODULE__TKINTER_TRUE
MODULE__UUID_FALSE
MODULE__UUID_TRUE
MODULE__SQLITE3_FALSE
@@ -821,8 +823,10 @@ DFLAGS
DTRACE
GDBM_LIBS
GDBM_CFLAGS
+X11_LIBS
+X11_CFLAGS
TCLTK_LIBS
-TCLTK_INCLUDES
+TCLTK_CFLAGS
LIBSQLITE3_LIBS
LIBSQLITE3_CFLAGS
LIBNSL_LIBS
@@ -1032,8 +1036,6 @@ with_system_ffi
with_system_libmpdec
with_decimal_contextvar
enable_loadable_sqlite_extensions
-with_tcltk_includes
-with_tcltk_libs
with_dbmliborder
enable_ipv6
with_doc_strings
@@ -1077,6 +1079,10 @@ LIBNSL_CFLAGS
LIBNSL_LIBS
LIBSQLITE3_CFLAGS
LIBSQLITE3_LIBS
+TCLTK_CFLAGS
+TCLTK_LIBS
+X11_CFLAGS
+X11_LIBS
GDBM_CFLAGS
GDBM_LIBS
ZLIB_CFLAGS
@@ -1801,10 +1807,6 @@ Optional Packages:
--with-decimal-contextvar
build _decimal module using a coroutine-local rather
than a thread-local context (default is yes)
- --with-tcltk-includes='-I...'
- override search for Tcl and Tk include files
- --with-tcltk-libs='-L...'
- override search for Tcl and Tk libs
--with-dbmliborder=db1:db2:...
override order to check db backends for dbm; a valid
value is a colon separated string with the backend
@@ -1880,6 +1882,11 @@ Some influential environment variables:
C compiler flags for LIBSQLITE3, overriding pkg-config
LIBSQLITE3_LIBS
linker flags for LIBSQLITE3, overriding pkg-config
+ TCLTK_CFLAGS
+ C compiler flags for TCLTK, overriding pkg-config
+ TCLTK_LIBS linker flags for TCLTK, overriding pkg-config
+ X11_CFLAGS C compiler flags for X11, overriding pkg-config
+ X11_LIBS linker flags for X11, overriding pkg-config
GDBM_CFLAGS C compiler flags for gdbm
GDBM_LIBS additional linker flags for gdbm
ZLIB_CFLAGS C compiler flags for ZLIB, overriding pkg-config
@@ -12334,50 +12341,280 @@ $as_echo "#define PY_SQLITE_ENABLE_LOAD_EXTENSION 1" >>confdefs.h
fi
-# Check for --with-tcltk-includes=path and --with-tcltk-libs=path
+found_tcltk=no
+for _QUERY in \
+ "tcl >= 8.5.12 tk >= 8.5.12" \
+ "tcl8.6 tk8.6" \
+ "tcl86 tk86" \
+ "tcl8.5 >= 8.5.12 tk8.5 >= 8.5.12" \
+ "tcl85 >= 8.5.12 tk85 >= 8.5.12" \
+; do
+ if test -n "$PKG_CONFIG" && \
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"\$_QUERY\""; } >&5
+ ($PKG_CONFIG --exists --print-errors "$_QUERY") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --with-tcltk-includes" >&5
-$as_echo_n "checking for --with-tcltk-includes... " >&6; }
+pkg_failed=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for TCLTK" >&5
+$as_echo_n "checking for TCLTK... " >&6; }
-# Check whether --with-tcltk-includes was given.
-if test "${with_tcltk_includes+set}" = set; then :
- withval=$with_tcltk_includes;
+if test -n "$TCLTK_CFLAGS"; then
+ pkg_cv_TCLTK_CFLAGS="$TCLTK_CFLAGS"
+ elif test -n "$PKG_CONFIG"; then
+ if test -n "$PKG_CONFIG" && \
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"\$_QUERY\""; } >&5
+ ($PKG_CONFIG --exists --print-errors "$_QUERY") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ pkg_cv_TCLTK_CFLAGS=`$PKG_CONFIG --cflags "$_QUERY" 2>/dev/null`
+ test "x$?" != "x0" && pkg_failed=yes
else
- with_tcltk_includes="default"
+ pkg_failed=yes
+fi
+ else
+ pkg_failed=untried
+fi
+if test -n "$TCLTK_LIBS"; then
+ pkg_cv_TCLTK_LIBS="$TCLTK_LIBS"
+ elif test -n "$PKG_CONFIG"; then
+ if test -n "$PKG_CONFIG" && \
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"\$_QUERY\""; } >&5
+ ($PKG_CONFIG --exists --print-errors "$_QUERY") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ pkg_cv_TCLTK_LIBS=`$PKG_CONFIG --libs "$_QUERY" 2>/dev/null`
+ test "x$?" != "x0" && pkg_failed=yes
+else
+ pkg_failed=yes
+fi
+ else
+ pkg_failed=untried
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_tcltk_includes" >&5
-$as_echo "$with_tcltk_includes" >&6; }
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --with-tcltk-libs" >&5
-$as_echo_n "checking for --with-tcltk-libs... " >&6; }
-# Check whether --with-tcltk-libs was given.
-if test "${with_tcltk_libs+set}" = set; then :
- withval=$with_tcltk_libs;
+
+if test $pkg_failed = yes; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+ _pkg_short_errors_supported=yes
else
- with_tcltk_libs="default"
+ _pkg_short_errors_supported=no
fi
+ if test $_pkg_short_errors_supported = yes; then
+ TCLTK_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$_QUERY" 2>&1`
+ else
+ TCLTK_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$_QUERY" 2>&1`
+ fi
+ # Put the nasty error message in config.log where it belongs
+ echo "$TCLTK_PKG_ERRORS" >&5
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_tcltk_libs" >&5
-$as_echo "$with_tcltk_libs" >&6; }
-if test "x$with_tcltk_includes" = xdefault || test "x$with_tcltk_libs" = xdefault
-then
- if test "x$with_tcltk_includes" != "x$with_tcltk_libs"
- then
- as_fn_error $? "use both --with-tcltk-includes='...' and --with-tcltk-libs='...' or neither" "$LINENO" 5
- fi
- if test -n "$PKG_CONFIG" && "$PKG_CONFIG" --exists tcl tk; then
- TCLTK_INCLUDES="`"$PKG_CONFIG" tcl tk --cflags-only-I 2>/dev/null`"
- TCLTK_LIBS="`"$PKG_CONFIG" tcl tk --libs 2>/dev/null`"
- else
- TCLTK_INCLUDES=""
- TCLTK_LIBS=""
- fi
+ found_tcltk=no
+elif test $pkg_failed = untried; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ found_tcltk=no
+else
+ TCLTK_CFLAGS=$pkg_cv_TCLTK_CFLAGS
+ TCLTK_LIBS=$pkg_cv_TCLTK_LIBS
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ found_tcltk=yes
+fi
+
+fi
+ if test "x$found_tcltk" = xyes; then :
+ break
+fi
+done
+
+if test "x$found_tcltk" = xno; then :
+
+ TCLTK_CFLAGS=${TCLTK_CFLAGS-""}
+ TCLTK_LIBS=${TCLTK_LIBS-""}
+
+fi
+
+case $ac_sys_system in #(
+ FreeBSD*) :
+
+ if test -n "$PKG_CONFIG" && \
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"x11\""; } >&5
+ ($PKG_CONFIG --exists --print-errors "x11") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+
+
+pkg_failed=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for X11" >&5
+$as_echo_n "checking for X11... " >&6; }
+
+if test -n "$X11_CFLAGS"; then
+ pkg_cv_X11_CFLAGS="$X11_CFLAGS"
+ elif test -n "$PKG_CONFIG"; then
+ if test -n "$PKG_CONFIG" && \
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"x11\""; } >&5
+ ($PKG_CONFIG --exists --print-errors "x11") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ pkg_cv_X11_CFLAGS=`$PKG_CONFIG --cflags "x11" 2>/dev/null`
+ test "x$?" != "x0" && pkg_failed=yes
+else
+ pkg_failed=yes
+fi
+ else
+ pkg_failed=untried
+fi
+if test -n "$X11_LIBS"; then
+ pkg_cv_X11_LIBS="$X11_LIBS"
+ elif test -n "$PKG_CONFIG"; then
+ if test -n "$PKG_CONFIG" && \
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"x11\""; } >&5
+ ($PKG_CONFIG --exists --print-errors "x11") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ pkg_cv_X11_LIBS=`$PKG_CONFIG --libs "x11" 2>/dev/null`
+ test "x$?" != "x0" && pkg_failed=yes
else
- TCLTK_INCLUDES="$with_tcltk_includes"
- TCLTK_LIBS="$with_tcltk_libs"
+ pkg_failed=yes
fi
+ else
+ pkg_failed=untried
+fi
+
+
+
+if test $pkg_failed = yes; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+ _pkg_short_errors_supported=yes
+else
+ _pkg_short_errors_supported=no
+fi
+ if test $_pkg_short_errors_supported = yes; then
+ X11_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "x11" 2>&1`
+ else
+ X11_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "x11" 2>&1`
+ fi
+ # Put the nasty error message in config.log where it belongs
+ echo "$X11_PKG_ERRORS" >&5
+
+ as_fn_error $? "Package requirements (x11) were not met:
+
+$X11_PKG_ERRORS
+
+Consider adjusting the PKG_CONFIG_PATH environment variable if you
+installed software in a non-standard prefix.
+
+Alternatively, you may set the environment variables X11_CFLAGS
+and X11_LIBS to avoid the need to call pkg-config.
+See the pkg-config man page for more details." "$LINENO" 5
+elif test $pkg_failed = untried; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "The pkg-config script could not be found or is too old. Make sure it
+is in your PATH or set the PKG_CONFIG environment variable to the full
+path to pkg-config.
+
+Alternatively, you may set the environment variables X11_CFLAGS
+and X11_LIBS to avoid the need to call pkg-config.
+See the pkg-config man page for more details.
+
+To get pkg-config, see <http://pkg-config.freedesktop.org/>.
+See \`config.log' for more details" "$LINENO" 5; }
+else
+ X11_CFLAGS=$pkg_cv_X11_CFLAGS
+ X11_LIBS=$pkg_cv_X11_LIBS
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+ TCLTK_CFLAGS="$TCLTK_CFLAGS $X11_CFLAGS"
+ TCLTK_LIBS="$TCLTK_LIBS $X11_LIBS"
+
+fi
+
+fi
+
+ ;; #(
+ *) :
+ ;;
+esac
+
+save_CFLAGS=$CFLAGS
+save_CPPFLAGS=$CPPFLAGS
+save_LDFLAGS=$LDFLAGS
+save_LIBS=$LIBS
+
+
+ CPPFLAGS="$TCLTK_CFLAGS $CFLAGS"
+ LIBS="$TCLTK_LIBS $LDFLAGS"
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+
+ #include <tcl.h>
+ #include <tk.h>
+ #if defined(TK_HEX_VERSION)
+ # if TK_HEX_VERSION < 0x0805020c
+ # error "Tk older than 8.5.12 not supported"
+ # endif
+ #endif
+ #if (TCL_MAJOR_VERSION < 8) || \
+ ((TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION < 5)) || \
+ ((TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION == 5) && (TCL_RELEASE_SERIAL < 12))
+ # error "Tcl older than 8.5.12 not supported"
+ #endif
+ #if (TK_MAJOR_VERSION < 8) || \
+ ((TK_MAJOR_VERSION == 8) && (TK_MINOR_VERSION < 5)) || \
+ ((TK_MAJOR_VERSION == 8) && (TK_MINOR_VERSION == 5) && (TK_RELEASE_SERIAL < 12))
+ # error "Tk older than 8.5.12 not supported"
+ #endif
+
+int
+main ()
+{
+
+ void *x1 = Tcl_Init;
+ void *x2 = Tk_Init;
+
+ ;
+ return 0;
+}
+
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ have_tcltk=yes
+ as_fn_append TCLTK_CFLAGS " -Wno-strict-prototypes -DWITH_APPINIT=1"
+
+else
+
+ have_tcltk=no
+
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+
+CFLAGS=$save_CFLAGS
+CPPFLAGS=$save_CPPFLAGS
+LDFLAGS=$save_LDFLAGS
+LIBS=$save_LIBS
+
+
@@ -18312,36 +18549,6 @@ _ACEOF
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for UCS-4 tcl" >&5
-$as_echo_n "checking for UCS-4 tcl... " >&6; }
-have_ucs4_tcl=no
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-#include <tcl.h>
-#if TCL_UTF_MAX != 6
-# error "NOT UCS4_TCL"
-#endif
-int
-main ()
-{
-
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
-
-
-$as_echo "#define HAVE_UCS4_TCL 1" >>confdefs.h
-
- have_ucs4_tcl=yes
-
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_ucs4_tcl" >&5
-$as_echo "$have_ucs4_tcl" >&6; }
-
# check whether wchar_t is signed or not
if test "$wchar_h" = yes
then
@@ -23224,6 +23431,40 @@ fi
$as_echo "$py_cv_module__uuid" >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module _tkinter" >&5
+$as_echo_n "checking for stdlib extension module _tkinter... " >&6; }
+ if test "$py_cv_module__tkinter" != "n/a"; then :
+
+ if true; then :
+ if test "$have_tcltk" = "yes"; then :
+ py_cv_module__tkinter=yes
+else
+ py_cv_module__tkinter=missing
+fi
+else
+ py_cv_module__tkinter=disabled
+fi
+
+fi
+ as_fn_append MODULE_BLOCK "MODULE__TKINTER=$py_cv_module__tkinter$as_nl"
+ if test "x$py_cv_module__tkinter" = xyes; then :
+
+ as_fn_append MODULE_BLOCK "MODULE__TKINTER_CFLAGS=$TCLTK_CFLAGS$as_nl"
+ as_fn_append MODULE_BLOCK "MODULE__TKINTER_LDFLAGS=$TCLTK_LIBS$as_nl"
+
+fi
+ if test "$py_cv_module__tkinter" = yes; then
+ MODULE__TKINTER_TRUE=
+ MODULE__TKINTER_FALSE='#'
+else
+ MODULE__TKINTER_TRUE='#'
+ MODULE__TKINTER_FALSE=
+fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $py_cv_module__tkinter" >&5
+$as_echo "$py_cv_module__tkinter" >&6; }
+
+
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for stdlib extension module zlib" >&5
$as_echo_n "checking for stdlib extension module zlib... " >&6; }
@@ -24084,6 +24325,10 @@ if test -z "${MODULE__UUID_TRUE}" && test -z "${MODULE__UUID_FALSE}"; then
as_fn_error $? "conditional \"MODULE__UUID\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
fi
+if test -z "${MODULE__TKINTER_TRUE}" && test -z "${MODULE__TKINTER_FALSE}"; then
+ as_fn_error $? "conditional \"MODULE__TKINTER\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
if test -z "${MODULE_ZLIB_TRUE}" && test -z "${MODULE_ZLIB_FALSE}"; then
as_fn_error $? "conditional \"MODULE_ZLIB\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
diff --git a/configure.ac b/configure.ac
index 566ff80aed3c7..7e8203ba85d1b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -3546,38 +3546,77 @@ AS_VAR_IF([enable_loadable_sqlite_extensions], [yes], [
[Define to 1 to build the sqlite module with loadable extensions support.])
])
-# Check for --with-tcltk-includes=path and --with-tcltk-libs=path
-AC_SUBST(TCLTK_INCLUDES)
-AC_SUBST(TCLTK_LIBS)
-AC_MSG_CHECKING(for --with-tcltk-includes)
-AC_ARG_WITH(tcltk-includes,
- AS_HELP_STRING([--with-tcltk-includes='-I...'], [override search for Tcl and Tk include files]),
- [],
- [with_tcltk_includes="default"])
-AC_MSG_RESULT($with_tcltk_includes)
-AC_MSG_CHECKING(for --with-tcltk-libs)
-AC_ARG_WITH(tcltk-libs,
- AS_HELP_STRING([--with-tcltk-libs='-L...'], [override search for Tcl and Tk libs]),
- [],
- [with_tcltk_libs="default"])
-AC_MSG_RESULT($with_tcltk_libs)
-if test "x$with_tcltk_includes" = xdefault || test "x$with_tcltk_libs" = xdefault
-then
- if test "x$with_tcltk_includes" != "x$with_tcltk_libs"
- then
- AC_MSG_ERROR([use both --with-tcltk-includes='...' and --with-tcltk-libs='...' or neither])
- fi
- if test -n "$PKG_CONFIG" && "$PKG_CONFIG" --exists tcl tk; then
- TCLTK_INCLUDES="`"$PKG_CONFIG" tcl tk --cflags-only-I 2>/dev/null`"
- TCLTK_LIBS="`"$PKG_CONFIG" tcl tk --libs 2>/dev/null`"
- else
- TCLTK_INCLUDES=""
- TCLTK_LIBS=""
- fi
-else
- TCLTK_INCLUDES="$with_tcltk_includes"
- TCLTK_LIBS="$with_tcltk_libs"
-fi
+dnl
+dnl Detect Tcl/Tk. Use pkg-config if available.
+dnl
+found_tcltk=no
+for _QUERY in \
+ "tcl >= 8.5.12 tk >= 8.5.12" \
+ "tcl8.6 tk8.6" \
+ "tcl86 tk86" \
+ "tcl8.5 >= 8.5.12 tk8.5 >= 8.5.12" \
+ "tcl85 >= 8.5.12 tk85 >= 8.5.12" \
+; do
+ PKG_CHECK_EXISTS([$_QUERY], [
+ PKG_CHECK_MODULES([TCLTK], [$_QUERY], [found_tcltk=yes], [found_tcltk=no])
+ ])
+ AS_VAR_IF([found_tcltk], [yes], [break])
+done
+
+AS_VAR_IF([found_tcltk], [no], [
+ TCLTK_CFLAGS=${TCLTK_CFLAGS-""}
+ TCLTK_LIBS=${TCLTK_LIBS-""}
+])
+
+dnl FreeBSD has an X11 dependency which is not implicitly resolved.
+AS_CASE([$ac_sys_system],
+ [FreeBSD*], [
+ PKG_CHECK_EXISTS([x11], [
+ PKG_CHECK_MODULES([X11], [x11], [
+ TCLTK_CFLAGS="$TCLTK_CFLAGS $X11_CFLAGS"
+ TCLTK_LIBS="$TCLTK_LIBS $X11_LIBS"
+ ])
+ ])
+ ]
+)
+
+WITH_SAVE_ENV([
+ CPPFLAGS="$TCLTK_CFLAGS $CFLAGS"
+ LIBS="$TCLTK_LIBS $LDFLAGS"
+
+ AC_LINK_IFELSE([
+ AC_LANG_PROGRAM([
+ #include <tcl.h>
+ #include <tk.h>
+ #if defined(TK_HEX_VERSION)
+ # if TK_HEX_VERSION < 0x0805020c
+ # error "Tk older than 8.5.12 not supported"
+ # endif
+ #endif
+ #if (TCL_MAJOR_VERSION < 8) || \
+ ((TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION < 5)) || \
+ ((TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION == 5) && (TCL_RELEASE_SERIAL < 12))
+ # error "Tcl older than 8.5.12 not supported"
+ #endif
+ #if (TK_MAJOR_VERSION < 8) || \
+ ((TK_MAJOR_VERSION == 8) && (TK_MINOR_VERSION < 5)) || \
+ ((TK_MAJOR_VERSION == 8) && (TK_MINOR_VERSION == 5) && (TK_RELEASE_SERIAL < 12))
+ # error "Tk older than 8.5.12 not supported"
+ #endif
+ ], [
+ void *x1 = Tcl_Init;
+ void *x2 = Tk_Init;
+ ])
+ ], [
+ have_tcltk=yes
+ dnl The X11/xlib.h file bundled in the Tk sources can cause function
+ dnl prototype warnings from the compiler. Since we cannot easily fix
+ dnl that, suppress the warnings here instead.
+ AS_VAR_APPEND([TCLTK_CFLAGS], [" -Wno-strict-prototypes -DWITH_APPINIT=1"])
+ ], [
+ have_tcltk=no
+ ])
+])
dnl check for _gdbmmodule dependencies
dnl NOTE: gdbm does not provide a pkgconf file.
@@ -5204,18 +5243,6 @@ then
AC_CHECK_SIZEOF(wchar_t, 4, [#include <wchar.h>])
fi
-AC_MSG_CHECKING(for UCS-4 tcl)
-have_ucs4_tcl=no
-AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
-#include <tcl.h>
-#if TCL_UTF_MAX != 6
-# error "NOT UCS4_TCL"
-#endif]], [[]])],[
- AC_DEFINE(HAVE_UCS4_TCL, 1, [Define this if you have tcl and TCL_UTF_MAX==6])
- have_ucs4_tcl=yes
-],[])
-AC_MSG_RESULT($have_ucs4_tcl)
-
# check whether wchar_t is signed or not
if test "$wchar_h" = yes
then
@@ -6704,6 +6731,8 @@ dnl PY_STDLIB_MOD([_tkinter], [], [], [], [])
PY_STDLIB_MOD([_uuid],
[], [test "$have_uuid" = "yes"],
[$LIBUUID_CFLAGS], [$LIBUUID_LIBS])
+PY_STDLIB_MOD([_tkinter], [],
+ [test "$have_tcltk" = "yes"], [$TCLTK_CFLAGS], [$TCLTK_LIBS])
dnl compression libs
PY_STDLIB_MOD([zlib], [], [test "$have_zlib" = yes],
diff --git a/pyconfig.h.in b/pyconfig.h.in
index ba77a27333d0c..3d2020c896934 100644
--- a/pyconfig.h.in
+++ b/pyconfig.h.in
@@ -1357,9 +1357,6 @@
`tzname'. */
#undef HAVE_TZNAME
-/* Define this if you have tcl and TCL_UTF_MAX==6 */
-#undef HAVE_UCS4_TCL
-
/* Define to 1 if you have the `umask' function. */
#undef HAVE_UMASK
diff --git a/setup.py b/setup.py
index 070ae9822bd5e..a1a24ce1551bd 100644
--- a/setup.py
+++ b/setup.py
@@ -213,28 +213,6 @@ def macosx_sdk_root():
return MACOS_SDK_ROOT
-def macosx_sdk_specified():
- """Returns true if an SDK was explicitly configured.
-
- True if an SDK was selected at configure time, either by specifying
- --enable-universalsdk=(something other than no or /) or by adding a
- -isysroot option to CFLAGS. In some cases, like when making
- decisions about macOS Tk framework paths, we need to be able to
- know whether the user explicitly asked to build with an SDK versus
- the implicit use of an SDK when header files are no longer
- installed on a running system by the Command Line Tools.
- """
- global MACOS_SDK_SPECIFIED
-
- # If already called, return cached result.
- if MACOS_SDK_SPECIFIED:
- return MACOS_SDK_SPECIFIED
-
- # Find the sdk root and set MACOS_SDK_SPECIFIED
- macosx_sdk_root()
- return MACOS_SDK_SPECIFIED
-
-
def is_macosx_sdk_path(path):
"""
Returns True if 'path' can be located in a macOS SDK
@@ -292,59 +270,6 @@ def find_file(filename, std_dirs, paths):
return None
-def find_library_file(compiler, libname, std_dirs, paths):
- result = compiler.find_library_file(std_dirs + paths, libname)
- if result is None:
- return None
-
- if MACOS:
- sysroot = macosx_sdk_root()
-
- # Check whether the found file is in one of the standard directories
- dirname = os.path.dirname(result)
- for p in std_dirs:
- # Ensure path doesn't end with path separator
- p = p.rstrip(os.sep)
-
- if MACOS and is_macosx_sdk_path(p):
- # Note that, as of Xcode 7, Apple SDKs may contain textual stub
- # libraries with .tbd extensions rather than the normal .dylib
- # shared libraries installed in /. The Apple compiler tool
- # chain handles this transparently but it can cause problems
- # for programs that are being built with an SDK and searching
- # for specific libraries. Distutils find_library_file() now
- # knows to also search for and return .tbd files. But callers
- # of find_library_file need to keep in mind that the base filename
- # of the returned SDK library file might have a different extension
- # from that of the library file installed on the running system,
- # for example:
- # /Applications/Xcode.app/Contents/Developer/Platforms/
- # MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk/
- # usr/lib/libedit.tbd
- # vs
- # /usr/lib/libedit.dylib
- if os.path.join(sysroot, p[1:]) == dirname:
- return [ ]
-
- if p == dirname:
- return [ ]
-
- # Otherwise, it must have been in one of the additional directories,
- # so we have to figure out which one.
- for p in paths:
- # Ensure path doesn't end with path separator
- p = p.rstrip(os.sep)
-
- if MACOS and is_macosx_sdk_path(p):
- if os.path.join(sysroot, p[1:]) == dirname:
- return [ p ]
-
- if p == dirname:
- return [p]
- else:
- assert False, "Internal error: Path not found in std_dirs or paths"
-
-
def validate_tzpath():
base_tzpath = sysconfig.get_config_var('TZPATH')
if not base_tzpath:
@@ -1433,8 +1358,7 @@ def detect_modules(self):
self.detect_decimal()
self.detect_ctypes()
self.detect_multiprocessing()
- if not self.detect_tkinter():
- self.missing.append('_tkinter')
+ self.detect_tkinter()
self.detect_uuid()
# Uncomment the next line if you want to play with xxmodule.c
@@ -1443,309 +1367,8 @@ def detect_modules(self):
self.addext(Extension('xxlimited', ['xxlimited.c']))
self.addext(Extension('xxlimited_35', ['xxlimited_35.c']))
- def detect_tkinter_fromenv(self):
- # Build _tkinter using the Tcl/Tk locations specified by
- # the _TCLTK_INCLUDES and _TCLTK_LIBS environment variables.
- # This method is meant to be invoked by detect_tkinter().
- #
- # The variables can be set via one of the following ways.
- #
- # - Automatically, at configuration time, by using pkg-config.
- # The tool is called by the configure script.
- # Additional pkg-config configuration paths can be set via the
- # PKG_CONFIG_PATH environment variable.
- #
- # PKG_CONFIG_PATH=".../lib/pkgconfig" ./configure ...
- #
- # - Explicitly, at configuration time by setting both
- # --with-tcltk-includes and --with-tcltk-libs.
- #
- # ./configure ... \
- # --with-tcltk-includes="-I/path/to/tclincludes \
- # -I/path/to/tkincludes"
- # --with-tcltk-libs="-L/path/to/tcllibs -ltclm.n \
- # -L/path/to/tklibs -ltkm.n"
- #
- # - Explicitly, at compile time, by passing TCLTK_INCLUDES and
- # TCLTK_LIBS to the make target.
- # This will override any configuration-time option.
- #
- # make TCLTK_INCLUDES="..." TCLTK_LIBS="..."
- #
- # This can be useful for building and testing tkinter with multiple
- # versions of Tcl/Tk. Note that a build of Tk depends on a particular
- # build of Tcl so you need to specify both arguments and use care when
- # overriding.
-
- # The _TCLTK variables are created in the Makefile sharedmods target.
- tcltk_includes = os.environ.get('_TCLTK_INCLUDES')
- tcltk_libs = os.environ.get('_TCLTK_LIBS')
- if not (tcltk_includes and tcltk_libs):
- # Resume default configuration search.
- return False
-
- extra_compile_args = tcltk_includes.split()
- extra_link_args = tcltk_libs.split()
- self.add(Extension('_tkinter', ['_tkinter.c', 'tkappinit.c'],
- define_macros=[('WITH_APPINIT', 1)],
- extra_compile_args = extra_compile_args,
- extra_link_args = extra_link_args))
- return True
-
- def detect_tkinter_darwin(self):
- # Build default _tkinter on macOS using Tcl and Tk frameworks.
- # This method is meant to be invoked by detect_tkinter().
- #
- # The macOS native Tk (AKA Aqua Tk) and Tcl are most commonly
- # built and installed as macOS framework bundles. However,
- # for several reasons, we cannot take full advantage of the
- # Apple-supplied compiler chain's -framework options here.
- # Instead, we need to find and pass to the compiler the
- # absolute paths of the Tcl and Tk headers files we want to use
- # and the absolute path to the directory containing the Tcl
- # and Tk frameworks for linking.
- #
- # We want to handle here two common use cases on macOS:
- # 1. Build and link with system-wide third-party or user-built
- # Tcl and Tk frameworks installed in /Library/Frameworks.
- # 2. Build and link using a user-specified macOS SDK so that the
- # built Python can be exported to other systems. In this case,
- # search only the SDK's /Library/Frameworks (normally empty)
- # and /System/Library/Frameworks.
- #
- # Any other use cases are handled either by detect_tkinter_fromenv(),
- # or detect_tkinter(). The former handles non-standard locations of
- # Tcl/Tk, defined via the _TCLTK_INCLUDES and _TCLTK_LIBS environment
- # variables. The latter handles any Tcl/Tk versions installed in
- # standard Unix directories.
- #
- # It would be desirable to also handle here the case where
- # you want to build and link with a framework build of Tcl and Tk
- # that is not in /Library/Frameworks, say, in your private
- # $HOME/Library/Frameworks directory or elsewhere. It turns
- # out to be difficult to make that work automatically here
- # without bringing into play more tools and magic. That case
- # can be handled using a recipe with the right arguments
- # to detect_tkinter_fromenv().
- #
- # Note also that the fallback case here is to try to use the
- # Apple-supplied Tcl and Tk frameworks in /System/Library but
- # be forewarned that they are deprecated by Apple and typically
- # out-of-date and buggy; their use should be avoided if at
- # all possible by installing a newer version of Tcl and Tk in
- # /Library/Frameworks before building Python without
- # an explicit SDK or by configuring build arguments explicitly.
-
- from os.path import join, exists
-
- sysroot = macosx_sdk_root() # path to the SDK or '/'
-
- if macosx_sdk_specified():
- # Use case #2: an SDK other than '/' was specified.
- # Only search there.
- framework_dirs = [
- join(sysroot, 'Library', 'Frameworks'),
- join(sysroot, 'System', 'Library', 'Frameworks'),
- ]
- else:
- # Use case #1: no explicit SDK selected.
- # Search the local system-wide /Library/Frameworks,
- # not the one in the default SDK, otherwise fall back to
- # /System/Library/Frameworks whose header files may be in
- # the default SDK or, on older systems, actually installed.
- framework_dirs = [
- join('/', 'Library', 'Frameworks'),
- join(sysroot, 'System', 'Library', 'Frameworks'),
- ]
-
- # Find the directory that contains the Tcl.framework and
- # Tk.framework bundles.
- for F in framework_dirs:
- # both Tcl.framework and Tk.framework should be present
- for fw in 'Tcl', 'Tk':
- if not exists(join(F, fw + '.framework')):
- break
- else:
- # ok, F is now directory with both frameworks. Continue
- # building
- break
- else:
- # Tk and Tcl frameworks not found. Normal "unix" tkinter search
- # will now resume.
- return False
-
- include_dirs = [
- join(F, fw + '.framework', H)
- for fw in ('Tcl', 'Tk')
- for H in ('Headers',)
- ]
-
- # Add the base framework directory as well
- compile_args = ['-F', F]
-
- # Do not build tkinter for archs that this Tk was not built with.
- cflags = sysconfig.get_config_vars('CFLAGS')[0]
- archs = re.findall(r'-arch\s+(\w+)', cflags)
-
- tmpfile = os.path.join(self.build_temp, 'tk.arch')
- if not os.path.exists(self.build_temp):
- os.makedirs(self.build_temp)
-
- run_command(
- "file {}/Tk.framework/Tk | grep 'for architecture' > {}".format(F, tmpfile)
- )
- with open(tmpfile) as fp:
- detected_archs = []
- for ln in fp:
- a = ln.split()[-1]
- if a in archs:
- detected_archs.append(ln.split()[-1])
- os.unlink(tmpfile)
-
- arch_args = []
- for a in detected_archs:
- arch_args.append('-arch')
- arch_args.append(a)
-
- compile_args += arch_args
- link_args = [','.join(['-Wl', '-F', F, '-framework', 'Tcl', '-framework', 'Tk']), *arch_args]
-
- # The X11/xlib.h file bundled in the Tk sources can cause function
- # prototype warnings from the compiler. Since we cannot easily fix
- # that, suppress the warnings here instead.
- if '-Wstrict-prototypes' in cflags.split():
- compile_args.append('-Wno-strict-prototypes')
-
- self.add(Extension('_tkinter', ['_tkinter.c', 'tkappinit.c'],
- define_macros=[('WITH_APPINIT', 1)],
- include_dirs=include_dirs,
- libraries=[],
- extra_compile_args=compile_args,
- extra_link_args=link_args))
- return True
-
def detect_tkinter(self):
- # The _tkinter module.
- #
- # Detection of Tcl/Tk is attempted in the following order:
- # - Through environment variables.
- # - Platform specific detection of Tcl/Tk (currently only macOS).
- # - Search of various standard Unix header/library paths.
- #
- # Detection stops at the first successful method.
-
- # Check for Tcl and Tk at the locations indicated by _TCLTK_INCLUDES
- # and _TCLTK_LIBS environment variables.
- if self.detect_tkinter_fromenv():
- return True
-
- # Rather than complicate the code below, detecting and building
- # AquaTk is a separate method. Only one Tkinter will be built on
- # Darwin - either AquaTk, if it is found, or X11 based Tk.
- if (MACOS and self.detect_tkinter_darwin()):
- return True
-
- # Assume we haven't found any of the libraries or include files
- # The versions with dots are used on Unix, and the versions without
- # dots on Windows, for detection by cygwin.
- tcllib = tklib = tcl_includes = tk_includes = None
- for version in ['8.6', '86', '8.5', '85', '8.4', '84', '8.3', '83',
- '8.2', '82', '8.1', '81', '8.0', '80']:
- tklib = self.compiler.find_library_file(self.lib_dirs,
- 'tk' + version)
- tcllib = self.compiler.find_library_file(self.lib_dirs,
- 'tcl' + version)
- if tklib and tcllib:
- # Exit the loop when we've found the Tcl/Tk libraries
- break
-
- # Now check for the header files
- if tklib and tcllib:
- # Check for the include files on Debian and {Free,Open}BSD, where
- # they're put in /usr/include/{tcl,tk}X.Y
- dotversion = version
- if '.' not in dotversion and "bsd" in HOST_PLATFORM.lower():
- # OpenBSD and FreeBSD use Tcl/Tk library names like libtcl83.a,
- # but the include subdirs are named like .../include/tcl8.3.
- dotversion = dotversion[:-1] + '.' + dotversion[-1]
- tcl_include_sub = []
- tk_include_sub = []
- for dir in self.inc_dirs:
- tcl_include_sub += [dir + os.sep + "tcl" + dotversion]
- tk_include_sub += [dir + os.sep + "tk" + dotversion]
- tk_include_sub += tcl_include_sub
- tcl_includes = find_file('tcl.h', self.inc_dirs, tcl_include_sub)
- tk_includes = find_file('tk.h', self.inc_dirs, tk_include_sub)
-
- if (tcllib is None or tklib is None or
- tcl_includes is None or tk_includes is None):
- self.announce("INFO: Can't locate Tcl/Tk libs and/or headers", 2)
- return False
-
- # OK... everything seems to be present for Tcl/Tk.
-
- include_dirs = []
- libs = []
- defs = []
- added_lib_dirs = []
- for dir in tcl_includes + tk_includes:
- if dir not in include_dirs:
- include_dirs.append(dir)
-
- # Check for various platform-specific directories
- if HOST_PLATFORM == 'sunos5':
- include_dirs.append('/usr/openwin/include')
- added_lib_dirs.append('/usr/openwin/lib')
- elif os.path.exists('/usr/X11R6/include'):
- include_dirs.append('/usr/X11R6/include')
- added_lib_dirs.append('/usr/X11R6/lib64')
- added_lib_dirs.append('/usr/X11R6/lib')
- elif os.path.exists('/usr/X11R5/include'):
- include_dirs.append('/usr/X11R5/include')
- added_lib_dirs.append('/usr/X11R5/lib')
- else:
- # Assume default location for X11
- include_dirs.append('/usr/X11/include')
- added_lib_dirs.append('/usr/X11/lib')
-
- # If Cygwin, then verify that X is installed before proceeding
- if CYGWIN:
- x11_inc = find_file('X11/Xlib.h', [], include_dirs)
- if x11_inc is None:
- return False
-
- # Check for BLT extension
- if self.compiler.find_library_file(self.lib_dirs + added_lib_dirs,
- 'BLT8.0'):
- defs.append( ('WITH_BLT', 1) )
- libs.append('BLT8.0')
- elif self.compiler.find_library_file(self.lib_dirs + added_lib_dirs,
- 'BLT'):
- defs.append( ('WITH_BLT', 1) )
- libs.append('BLT')
-
- # Add the Tcl/Tk libraries
- libs.append('tk'+ version)
- libs.append('tcl'+ version)
-
- # Finally, link with the X11 libraries (not appropriate on cygwin)
- if not CYGWIN:
- libs.append('X11')
-
- # XXX handle these, but how to detect?
- # *** Uncomment and edit for PIL (TkImaging) extension only:
- # -DWITH_PIL -I../Extensions/Imaging/libImaging tkImaging.c \
- # *** Uncomment and edit for TOGL extension only:
- # -DWITH_TOGL togl.c \
- # *** Uncomment these for TOGL extension only:
- # -lGL -lGLU -lXext -lXmu \
-
- self.add(Extension('_tkinter', ['_tkinter.c', 'tkappinit.c'],
- define_macros=[('WITH_APPINIT', 1)] + defs,
- include_dirs=include_dirs,
- libraries=libs,
- library_dirs=added_lib_dirs))
- return True
+ self.addext(Extension('_tkinter', ['_tkinter.c', 'tkappinit.c']))
def configure_ctypes(self, ext):
return True
1
0
https://github.com/python/cpython/commit/7fc39a21cb85163a456eab91b52e5fe85e…
commit: 7fc39a21cb85163a456eab91b52e5fe85e7f7e3e
branch: main
author: Victor Stinner <vstinner(a)python.org>
committer: vstinner <vstinner(a)python.org>
date: 2022-03-31T10:03:13+02:00
summary:
bpo-47164: Add _PyCFunctionObject_CAST() macr (GH-32190)
Add _PyCFunctionObject_CAST() and _PyCMethodObject_CAST() macros to
make macros casting their argument easier to read, but also to check
the type of their input in debug mode: assert(PyCFunction_Check(func)
and assert(PyCMethod_Check(func).
Reformat also PyCFunction_XXX() macros for readability.
files:
M Include/cpython/methodobject.h
diff --git a/Include/cpython/methodobject.h b/Include/cpython/methodobject.h
index 7ecbfe3b5e2fe..46d177793fc4c 100644
--- a/Include/cpython/methodobject.h
+++ b/Include/cpython/methodobject.h
@@ -7,18 +7,23 @@ PyAPI_DATA(PyTypeObject) PyCMethod_Type;
#define PyCMethod_CheckExact(op) Py_IS_TYPE(op, &PyCMethod_Type)
#define PyCMethod_Check(op) PyObject_TypeCheck(op, &PyCMethod_Type)
+#define _PyCFunctionObject_CAST(func) \
+ (assert(PyCFunction_Check(func)), (PyCFunctionObject *)(func))
+#define _PyCMethodObject_CAST(func) \
+ (assert(PyCMethod_Check(func)), (PyCMethodObject *)(func))
+
/* Macros for direct access to these values. Type checks are *not*
done, so use with care. */
#define PyCFunction_GET_FUNCTION(func) \
- (((PyCFunctionObject *)func) -> m_ml -> ml_meth)
+ (_PyCFunctionObject_CAST(func)->m_ml->ml_meth)
#define PyCFunction_GET_SELF(func) \
- (((PyCFunctionObject *)func) -> m_ml -> ml_flags & METH_STATIC ? \
- NULL : ((PyCFunctionObject *)func) -> m_self)
+ (_PyCFunctionObject_CAST(func)->m_ml->ml_flags & METH_STATIC ? \
+ NULL : _PyCFunctionObject_CAST(func)->m_self)
#define PyCFunction_GET_FLAGS(func) \
- (((PyCFunctionObject *)func) -> m_ml -> ml_flags)
+ (_PyCFunctionObject_CAST(func)->m_ml->ml_flags)
#define PyCFunction_GET_CLASS(func) \
- (((PyCFunctionObject *)func) -> m_ml -> ml_flags & METH_METHOD ? \
- ((PyCMethodObject *)func) -> mm_class : NULL)
+ (_PyCFunctionObject_CAST(func)->m_ml->ml_flags & METH_METHOD ? \
+ _PyCMethodObject_CAST(func)->mm_class : NULL)
typedef struct {
PyObject_HEAD
1
0
https://github.com/python/cpython/commit/f0bc69485677ae8973685866ada0982976…
commit: f0bc69485677ae8973685866ada0982976d3878f
branch: main
author: Victor Stinner <vstinner(a)python.org>
committer: vstinner <vstinner(a)python.org>
date: 2022-03-31T10:02:34+02:00
summary:
bpo-47164: Add _PyCFunction_CAST() macro (GH-32192)
Use the macro in C files of the Python/ directory.
files:
M Doc/c-api/structures.rst
M Include/methodobject.h
M Python/_warnings.c
M Python/bltinmodule.c
M Python/context.c
M Python/hamt.c
M Python/sysmodule.c
M Python/traceback.c
diff --git a/Doc/c-api/structures.rst b/Doc/c-api/structures.rst
index 49f2a614e3507..3270d7d8fba45 100644
--- a/Doc/c-api/structures.rst
+++ b/Doc/c-api/structures.rst
@@ -342,6 +342,9 @@ There are these calling conventions:
hold a reference to the module or object instance. In all cases the second
parameter will be ``NULL``.
+ The function must have 2 parameters. Since the second parameter is unused,
+ :c:macro:`Py_UNUSED` can be used to prevent a compiler warning.
+
.. data:: METH_O
diff --git a/Include/methodobject.h b/Include/methodobject.h
index 5d2e06c3e7cea..959e77512200c 100644
--- a/Include/methodobject.h
+++ b/Include/methodobject.h
@@ -26,6 +26,24 @@ typedef PyObject *(*_PyCFunctionFastWithKeywords) (PyObject *,
typedef PyObject *(*PyCMethod)(PyObject *, PyTypeObject *, PyObject *const *,
size_t, PyObject *);
+// Cast an function to the PyCFunction type to use it with PyMethodDef.
+//
+// This macro can be used to prevent compiler warnings if the first parameter
+// uses a different pointer type than PyObject* (ex: METH_VARARGS and METH_O
+// calling conventions).
+//
+// The macro can also be used for METH_FASTCALL and METH_VARARGS|METH_KEYWORDS
+// calling conventions to avoid compiler warnings because the function has more
+// than 2 parameters. The macro first casts the function to the
+// "void func(void)" type to prevent compiler warnings.
+//
+// If a function is declared with the METH_NOARGS calling convention, it must
+// have 2 parameters. Since the second parameter is unused, Py_UNUSED() can be
+// used to prevent a compiler warning. If the function has a single parameter,
+// it triggers an undefined behavior when Python calls it with 2 parameters
+// (bpo-33012).
+#define _PyCFunction_CAST(func) ((PyCFunction)(void(*)(void))(func))
+
PyAPI_FUNC(PyCFunction) PyCFunction_GetFunction(PyObject *);
PyAPI_FUNC(PyObject *) PyCFunction_GetSelf(PyObject *);
PyAPI_FUNC(int) PyCFunction_GetFlags(PyObject *);
diff --git a/Python/_warnings.c b/Python/_warnings.c
index be962e76cd801..942308b357e33 100644
--- a/Python/_warnings.c
+++ b/Python/_warnings.c
@@ -1078,7 +1078,7 @@ warnings_warn_explicit(PyObject *self, PyObject *args, PyObject *kwds)
}
static PyObject *
-warnings_filters_mutated(PyObject *self, PyObject *args)
+warnings_filters_mutated(PyObject *self, PyObject *Py_UNUSED(args))
{
PyInterpreterState *interp = get_current_interp();
if (interp == NULL) {
@@ -1353,9 +1353,9 @@ PyDoc_STRVAR(warn_explicit_doc,
static PyMethodDef warnings_functions[] = {
WARNINGS_WARN_METHODDEF
- {"warn_explicit", (PyCFunction)(void(*)(void))warnings_warn_explicit,
+ {"warn_explicit", _PyCFunction_CAST(warnings_warn_explicit),
METH_VARARGS | METH_KEYWORDS, warn_explicit_doc},
- {"_filters_mutated", (PyCFunction)warnings_filters_mutated, METH_NOARGS,
+ {"_filters_mutated", _PyCFunction_CAST(warnings_filters_mutated), METH_NOARGS,
NULL},
/* XXX(brett.cannon): add showwarning? */
/* XXX(brett.cannon): Reasonable to add formatwarning? */
diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c
index 332f4cbbd0dcc..9cfecc521d90c 100644
--- a/Python/bltinmodule.c
+++ b/Python/bltinmodule.c
@@ -613,7 +613,7 @@ filter_reduce(filterobject *lz, PyObject *Py_UNUSED(ignored))
PyDoc_STRVAR(reduce_doc, "Return state information for pickling.");
static PyMethodDef filter_methods[] = {
- {"__reduce__", (PyCFunction)filter_reduce, METH_NOARGS, reduce_doc},
+ {"__reduce__", _PyCFunction_CAST(filter_reduce), METH_NOARGS, reduce_doc},
{NULL, NULL} /* sentinel */
};
@@ -1354,7 +1354,7 @@ map_reduce(mapobject *lz, PyObject *Py_UNUSED(ignored))
}
static PyMethodDef map_methods[] = {
- {"__reduce__", (PyCFunction)map_reduce, METH_NOARGS, reduce_doc},
+ {"__reduce__", _PyCFunction_CAST(map_reduce), METH_NOARGS, reduce_doc},
{NULL, NULL} /* sentinel */
};
@@ -2321,7 +2321,7 @@ PyDoc_STRVAR(builtin_sorted__doc__,
"reverse flag can be set to request the result in descending order.");
#define BUILTIN_SORTED_METHODDEF \
- {"sorted", (PyCFunction)(void(*)(void))builtin_sorted, METH_FASTCALL | METH_KEYWORDS, builtin_sorted__doc__},
+ {"sorted", _PyCFunction_CAST(builtin_sorted), METH_FASTCALL | METH_KEYWORDS, builtin_sorted__doc__},
static PyObject *
builtin_sorted(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
@@ -2839,8 +2839,8 @@ zip_setstate(zipobject *lz, PyObject *state)
}
static PyMethodDef zip_methods[] = {
- {"__reduce__", (PyCFunction)zip_reduce, METH_NOARGS, reduce_doc},
- {"__setstate__", (PyCFunction)zip_setstate, METH_O, setstate_doc},
+ {"__reduce__", _PyCFunction_CAST(zip_reduce), METH_NOARGS, reduce_doc},
+ {"__setstate__", _PyCFunction_CAST(zip_setstate), METH_O, setstate_doc},
{NULL} /* sentinel */
};
@@ -2904,7 +2904,7 @@ PyTypeObject PyZip_Type = {
static PyMethodDef builtin_methods[] = {
- {"__build_class__", (PyCFunction)(void(*)(void))builtin___build_class__,
+ {"__build_class__", _PyCFunction_CAST(builtin___build_class__),
METH_FASTCALL | METH_KEYWORDS, build_class_doc},
BUILTIN___IMPORT___METHODDEF
BUILTIN_ABS_METHODDEF
@@ -2912,17 +2912,17 @@ static PyMethodDef builtin_methods[] = {
BUILTIN_ANY_METHODDEF
BUILTIN_ASCII_METHODDEF
BUILTIN_BIN_METHODDEF
- {"breakpoint", (PyCFunction)(void(*)(void))builtin_breakpoint, METH_FASTCALL | METH_KEYWORDS, breakpoint_doc},
+ {"breakpoint", _PyCFunction_CAST(builtin_breakpoint), METH_FASTCALL | METH_KEYWORDS, breakpoint_doc},
BUILTIN_CALLABLE_METHODDEF
BUILTIN_CHR_METHODDEF
BUILTIN_COMPILE_METHODDEF
BUILTIN_DELATTR_METHODDEF
- {"dir", builtin_dir, METH_VARARGS, dir_doc},
+ {"dir", builtin_dir, METH_VARARGS, dir_doc},
BUILTIN_DIVMOD_METHODDEF
BUILTIN_EVAL_METHODDEF
BUILTIN_EXEC_METHODDEF
BUILTIN_FORMAT_METHODDEF
- {"getattr", (PyCFunction)(void(*)(void))builtin_getattr, METH_FASTCALL, getattr_doc},
+ {"getattr", _PyCFunction_CAST(builtin_getattr), METH_FASTCALL, getattr_doc},
BUILTIN_GLOBALS_METHODDEF
BUILTIN_HASATTR_METHODDEF
BUILTIN_HASH_METHODDEF
@@ -2931,13 +2931,13 @@ static PyMethodDef builtin_methods[] = {
BUILTIN_INPUT_METHODDEF
BUILTIN_ISINSTANCE_METHODDEF
BUILTIN_ISSUBCLASS_METHODDEF
- {"iter", (PyCFunction)(void(*)(void))builtin_iter, METH_FASTCALL, iter_doc},
+ {"iter", _PyCFunction_CAST(builtin_iter), METH_FASTCALL, iter_doc},
BUILTIN_AITER_METHODDEF
BUILTIN_LEN_METHODDEF
BUILTIN_LOCALS_METHODDEF
- {"max", (PyCFunction)(void(*)(void))builtin_max, METH_VARARGS | METH_KEYWORDS, max_doc},
- {"min", (PyCFunction)(void(*)(void))builtin_min, METH_VARARGS | METH_KEYWORDS, min_doc},
- {"next", (PyCFunction)(void(*)(void))builtin_next, METH_FASTCALL, next_doc},
+ {"max", _PyCFunction_CAST(builtin_max), METH_VARARGS | METH_KEYWORDS, max_doc},
+ {"min", _PyCFunction_CAST(builtin_min), METH_VARARGS | METH_KEYWORDS, min_doc},
+ {"next", _PyCFunction_CAST(builtin_next), METH_FASTCALL, next_doc},
BUILTIN_ANEXT_METHODDEF
BUILTIN_OCT_METHODDEF
BUILTIN_ORD_METHODDEF
diff --git a/Python/context.c b/Python/context.c
index f3033d9b649af..a77cd14544edc 100644
--- a/Python/context.c
+++ b/Python/context.c
@@ -685,7 +685,7 @@ static PyMethodDef PyContext_methods[] = {
_CONTEXTVARS_CONTEXT_KEYS_METHODDEF
_CONTEXTVARS_CONTEXT_VALUES_METHODDEF
_CONTEXTVARS_CONTEXT_COPY_METHODDEF
- {"run", (PyCFunction)(void(*)(void))context_run, METH_FASTCALL | METH_KEYWORDS, NULL},
+ {"run", _PyCFunction_CAST(context_run), METH_FASTCALL | METH_KEYWORDS, NULL},
{NULL, NULL}
};
diff --git a/Python/hamt.c b/Python/hamt.c
index cbfe4459d3ed0..c3cb4e6fda450 100644
--- a/Python/hamt.c
+++ b/Python/hamt.c
@@ -2845,14 +2845,14 @@ hamt_py_values(PyHamtObject *self, PyObject *args)
}
static PyObject *
-hamt_py_keys(PyHamtObject *self, PyObject *args)
+hamt_py_keys(PyHamtObject *self, PyObject *Py_UNUSED(args))
{
return _PyHamt_NewIterKeys(self);
}
#ifdef Py_DEBUG
static PyObject *
-hamt_py_dump(PyHamtObject *self, PyObject *args)
+hamt_py_dump(PyHamtObject *self, PyObject *Py_UNUSED(args))
{
return hamt_dump(self);
}
@@ -2860,14 +2860,14 @@ hamt_py_dump(PyHamtObject *self, PyObject *args)
static PyMethodDef PyHamt_methods[] = {
- {"set", (PyCFunction)hamt_py_set, METH_VARARGS, NULL},
- {"get", (PyCFunction)hamt_py_get, METH_VARARGS, NULL},
- {"delete", (PyCFunction)hamt_py_delete, METH_O, NULL},
- {"items", (PyCFunction)hamt_py_items, METH_NOARGS, NULL},
- {"keys", (PyCFunction)hamt_py_keys, METH_NOARGS, NULL},
- {"values", (PyCFunction)hamt_py_values, METH_NOARGS, NULL},
+ {"set", _PyCFunction_CAST(hamt_py_set), METH_VARARGS, NULL},
+ {"get", _PyCFunction_CAST(hamt_py_get), METH_VARARGS, NULL},
+ {"delete", _PyCFunction_CAST(hamt_py_delete), METH_O, NULL},
+ {"items", _PyCFunction_CAST(hamt_py_items), METH_NOARGS, NULL},
+ {"keys", _PyCFunction_CAST(hamt_py_keys), METH_NOARGS, NULL},
+ {"values", _PyCFunction_CAST(hamt_py_values), METH_NOARGS, NULL},
#ifdef Py_DEBUG
- {"__dump__", (PyCFunction)hamt_py_dump, METH_NOARGS, NULL},
+ {"__dump__", _PyCFunction_CAST(hamt_py_dump), METH_NOARGS, NULL},
#endif
{NULL, NULL}
};
diff --git a/Python/sysmodule.c b/Python/sysmodule.c
index 6322af5f5ca81..5765e9ef6577c 100644
--- a/Python/sysmodule.c
+++ b/Python/sysmodule.c
@@ -1929,8 +1929,8 @@ sys_getandroidapilevel_impl(PyObject *module)
static PyMethodDef sys_methods[] = {
/* Might as well keep this in alphabetic order */
SYS_ADDAUDITHOOK_METHODDEF
- {"audit", (PyCFunction)(void(*)(void))sys_audit, METH_FASTCALL, audit_doc },
- {"breakpointhook", (PyCFunction)(void(*)(void))sys_breakpointhook,
+ {"audit", _PyCFunction_CAST(sys_audit), METH_FASTCALL, audit_doc },
+ {"breakpointhook", _PyCFunction_CAST(sys_breakpointhook),
METH_FASTCALL | METH_KEYWORDS, breakpointhook_doc},
SYS__CLEAR_TYPE_CACHE_METHODDEF
SYS__CURRENT_FRAMES_METHODDEF
@@ -1944,18 +1944,18 @@ static PyMethodDef sys_methods[] = {
SYS_GETDLOPENFLAGS_METHODDEF
SYS_GETALLOCATEDBLOCKS_METHODDEF
#ifdef Py_STATS
- {"getdxp", _Py_GetDXProfile, METH_VARARGS},
+ {"getdxp", _Py_GetDXProfile, METH_VARARGS},
#endif
SYS_GETFILESYSTEMENCODING_METHODDEF
SYS_GETFILESYSTEMENCODEERRORS_METHODDEF
SYS__GETQUICKENEDCOUNT_METHODDEF
#ifdef Py_TRACE_REFS
- {"getobjects", _Py_GetObjects, METH_VARARGS},
+ {"getobjects", _Py_GetObjects, METH_VARARGS},
#endif
SYS_GETTOTALREFCOUNT_METHODDEF
SYS_GETREFCOUNT_METHODDEF
SYS_GETRECURSIONLIMIT_METHODDEF
- {"getsizeof", (PyCFunction)(void(*)(void))sys_getsizeof,
+ {"getsizeof", _PyCFunction_CAST(sys_getsizeof),
METH_VARARGS | METH_KEYWORDS, getsizeof_doc},
SYS__GETFRAME_METHODDEF
SYS_GETWINDOWSVERSION_METHODDEF
@@ -1966,21 +1966,21 @@ static PyMethodDef sys_methods[] = {
SYS_SETSWITCHINTERVAL_METHODDEF
SYS_GETSWITCHINTERVAL_METHODDEF
SYS_SETDLOPENFLAGS_METHODDEF
- {"setprofile", sys_setprofile, METH_O, setprofile_doc},
+ {"setprofile", sys_setprofile, METH_O, setprofile_doc},
SYS_GETPROFILE_METHODDEF
SYS_SETRECURSIONLIMIT_METHODDEF
- {"settrace", sys_settrace, METH_O, settrace_doc},
+ {"settrace", sys_settrace, METH_O, settrace_doc},
SYS_GETTRACE_METHODDEF
SYS_CALL_TRACING_METHODDEF
SYS__DEBUGMALLOCSTATS_METHODDEF
SYS_SET_COROUTINE_ORIGIN_TRACKING_DEPTH_METHODDEF
SYS_GET_COROUTINE_ORIGIN_TRACKING_DEPTH_METHODDEF
- {"set_asyncgen_hooks", (PyCFunction)(void(*)(void))sys_set_asyncgen_hooks,
+ {"set_asyncgen_hooks", _PyCFunction_CAST(sys_set_asyncgen_hooks),
METH_VARARGS | METH_KEYWORDS, set_asyncgen_hooks_doc},
SYS_GET_ASYNCGEN_HOOKS_METHODDEF
SYS_GETANDROIDAPILEVEL_METHODDEF
SYS_UNRAISABLEHOOK_METHODDEF
- {NULL, NULL} /* sentinel */
+ {NULL, NULL} // sentinel
};
diff --git a/Python/traceback.c b/Python/traceback.c
index f5c1849101a21..0d0eb954c232f 100644
--- a/Python/traceback.c
+++ b/Python/traceback.c
@@ -149,7 +149,7 @@ tb_next_set(PyTracebackObject *self, PyObject *new_next, void *Py_UNUSED(_))
static PyMethodDef tb_methods[] = {
- {"__dir__", (PyCFunction)tb_dir, METH_NOARGS},
+ {"__dir__", _PyCFunction_CAST(tb_dir), METH_NOARGS},
{NULL, NULL, 0, NULL},
};
1
0
https://github.com/python/cpython/commit/c14d7e4b816134b8e93ece4066a86d2296…
commit: c14d7e4b816134b8e93ece4066a86d229631ce96
branch: main
author: Victor Stinner <vstinner(a)python.org>
committer: vstinner <vstinner(a)python.org>
date: 2022-03-31T09:59:27+02:00
summary:
bpo-47164: Add _PyASCIIObject_CAST() macro (GH-32191)
Add macros to cast objects to PyASCIIObject*, PyCompactUnicodeObject*
and PyUnicodeObject*: _PyASCIIObject_CAST(),
_PyCompactUnicodeObject_CAST() and _PyUnicodeObject_CAST(). Using
these new macros make the code more readable and check their argument
with: assert(PyUnicode_Check(op)).
Remove redundant assert(PyUnicode_Check(op)) in macros using directly
or indirectly these new CAST macros.
Replacing existing casts with these macros.
files:
M Include/cpython/unicodeobject.h
M Include/unicodeobject.h
M Modules/_collectionsmodule.c
M Objects/dictobject.c
M Objects/setobject.c
M Objects/typeobject.c
M Objects/unicodeobject.c
M Python/traceback.c
diff --git a/Include/cpython/unicodeobject.h b/Include/cpython/unicodeobject.h
index 77a171b86bff4..69e4abfb5c442 100644
--- a/Include/cpython/unicodeobject.h
+++ b/Include/cpython/unicodeobject.h
@@ -234,6 +234,15 @@ PyAPI_FUNC(int) _PyUnicode_CheckConsistency(
PyObject *op,
int check_content);
+
+#define _PyASCIIObject_CAST(op) \
+ (assert(PyUnicode_Check(op)), (PyASCIIObject*)(op))
+#define _PyCompactUnicodeObject_CAST(op) \
+ (assert(PyUnicode_Check(op)), (PyCompactUnicodeObject*)(op))
+#define _PyUnicodeObject_CAST(op) \
+ (assert(PyUnicode_Check(op)), (PyUnicodeObject*)(op))
+
+
/* Fast access macros */
/* Returns the deprecated Py_UNICODE representation's size in code units
@@ -243,11 +252,10 @@ PyAPI_FUNC(int) _PyUnicode_CheckConsistency(
/* Py_DEPRECATED(3.3) */
#define PyUnicode_GET_SIZE(op) \
- (assert(PyUnicode_Check(op)), \
- (((PyASCIIObject *)(op))->wstr) ? \
+ (_PyASCIIObject_CAST(op)->wstr ? \
PyUnicode_WSTR_LENGTH(op) : \
((void)PyUnicode_AsUnicode(_PyObject_CAST(op)),\
- assert(((PyASCIIObject *)(op))->wstr), \
+ assert(_PyASCIIObject_CAST(op)->wstr), \
PyUnicode_WSTR_LENGTH(op)))
/* Py_DEPRECATED(3.3) */
@@ -261,9 +269,8 @@ PyAPI_FUNC(int) _PyUnicode_CheckConsistency(
/* Py_DEPRECATED(3.3) */
#define PyUnicode_AS_UNICODE(op) \
- (assert(PyUnicode_Check(op)), \
- (((PyASCIIObject *)(op))->wstr) ? (((PyASCIIObject *)(op))->wstr) : \
- PyUnicode_AsUnicode(_PyObject_CAST(op)))
+ (_PyASCIIObject_CAST(op)->wstr ? _PyASCIIObject_CAST(op)->wstr : \
+ PyUnicode_AsUnicode(_PyObject_CAST(op)))
/* Py_DEPRECATED(3.3) */
#define PyUnicode_AS_DATA(op) \
@@ -281,25 +288,24 @@ PyAPI_FUNC(int) _PyUnicode_CheckConsistency(
/* Use only if you know it's a string */
#define PyUnicode_CHECK_INTERNED(op) \
- (((PyASCIIObject *)(op))->state.interned)
+ (_PyASCIIObject_CAST(op)->state.interned)
/* Return true if the string contains only ASCII characters, or 0 if not. The
string may be compact (PyUnicode_IS_COMPACT_ASCII) or not, but must be
ready. */
#define PyUnicode_IS_ASCII(op) \
- (assert(PyUnicode_Check(op)), \
- assert(PyUnicode_IS_READY(op)), \
- ((PyASCIIObject*)op)->state.ascii)
+ (assert(PyUnicode_IS_READY(op)), \
+ _PyASCIIObject_CAST(op)->state.ascii)
/* Return true if the string is compact or 0 if not.
No type checks or Ready calls are performed. */
#define PyUnicode_IS_COMPACT(op) \
- (((PyASCIIObject*)(op))->state.compact)
+ (_PyASCIIObject_CAST(op)->state.compact)
/* Return true if the string is a compact ASCII string (use PyASCIIObject
structure), or 0 if not. No type checks or Ready calls are performed. */
#define PyUnicode_IS_COMPACT_ASCII(op) \
- (((PyASCIIObject*)op)->state.ascii && PyUnicode_IS_COMPACT(op))
+ (_PyASCIIObject_CAST(op)->state.ascii && PyUnicode_IS_COMPACT(op))
enum PyUnicode_Kind {
/* String contains only wstr byte characters. This is only possible
@@ -323,23 +329,21 @@ enum PyUnicode_Kind {
/* Return one of the PyUnicode_*_KIND values defined above. */
#define PyUnicode_KIND(op) \
- (assert(PyUnicode_Check(op)), \
- assert(PyUnicode_IS_READY(op)), \
- ((PyASCIIObject *)(op))->state.kind)
+ (assert(PyUnicode_IS_READY(op)), \
+ _PyASCIIObject_CAST(op)->state.kind)
/* Return a void pointer to the raw unicode buffer. */
#define _PyUnicode_COMPACT_DATA(op) \
- (PyUnicode_IS_ASCII(op) ? \
- ((void*)((PyASCIIObject*)(op) + 1)) : \
- ((void*)((PyCompactUnicodeObject*)(op) + 1)))
+ (PyUnicode_IS_ASCII(op) ? \
+ ((void*)(_PyASCIIObject_CAST(op) + 1)) : \
+ ((void*)(_PyCompactUnicodeObject_CAST(op) + 1)))
#define _PyUnicode_NONCOMPACT_DATA(op) \
- (assert(((PyUnicodeObject*)(op))->data.any), \
- ((((PyUnicodeObject *)(op))->data.any)))
+ (assert(_PyUnicodeObject_CAST(op)->data.any), \
+ (_PyUnicodeObject_CAST(op)->data.any))
#define PyUnicode_DATA(op) \
- (assert(PyUnicode_Check(op)), \
- PyUnicode_IS_COMPACT(op) ? _PyUnicode_COMPACT_DATA(op) : \
+ (PyUnicode_IS_COMPACT(op) ? _PyUnicode_COMPACT_DATA(op) : \
_PyUnicode_NONCOMPACT_DATA(op))
/* In the access macros below, "kind" may be evaluated more than once.
@@ -386,8 +390,7 @@ enum PyUnicode_Kind {
PyUnicode_READ_CHAR, for multiple consecutive reads callers should
cache kind and use PyUnicode_READ instead. */
#define PyUnicode_READ_CHAR(unicode, index) \
- (assert(PyUnicode_Check(unicode)), \
- assert(PyUnicode_IS_READY(unicode)), \
+ (assert(PyUnicode_IS_READY(unicode)), \
(Py_UCS4) \
(PyUnicode_KIND((unicode)) == PyUnicode_1BYTE_KIND ? \
((const Py_UCS1 *)(PyUnicode_DATA((unicode))))[(index)] : \
@@ -401,23 +404,21 @@ enum PyUnicode_Kind {
the string has it's canonical representation set before calling
this macro. Call PyUnicode_(FAST_)Ready to ensure that. */
#define PyUnicode_GET_LENGTH(op) \
- (assert(PyUnicode_Check(op)), \
- assert(PyUnicode_IS_READY(op)), \
- ((PyASCIIObject *)(op))->length)
+ (assert(PyUnicode_IS_READY(op)), \
+ _PyASCIIObject_CAST(op)->length)
/* Fast check to determine whether an object is ready. Equivalent to
- PyUnicode_IS_COMPACT(op) || ((PyUnicodeObject*)(op))->data.any */
+ PyUnicode_IS_COMPACT(op) || _PyUnicodeObject_CAST(op)->data.any */
-#define PyUnicode_IS_READY(op) (((PyASCIIObject*)op)->state.ready)
+#define PyUnicode_IS_READY(op) (_PyASCIIObject_CAST(op)->state.ready)
/* PyUnicode_READY() does less work than _PyUnicode_Ready() in the best
case. If the canonical representation is not yet set, it will still call
_PyUnicode_Ready().
Returns 0 on success and -1 on errors. */
#define PyUnicode_READY(op) \
- (assert(PyUnicode_Check(op)), \
- (PyUnicode_IS_READY(op) ? \
+ ((PyUnicode_IS_READY(op) ? \
0 : _PyUnicode_Ready(_PyObject_CAST(op))))
/* Return a maximum character value which is suitable for creating another
@@ -436,8 +437,8 @@ enum PyUnicode_Kind {
Py_DEPRECATED(3.3)
static inline Py_ssize_t PyUnicode_WSTR_LENGTH(PyObject *op) {
return PyUnicode_IS_COMPACT_ASCII(op) ?
- ((PyASCIIObject*)op)->length :
- ((PyCompactUnicodeObject*)op)->wstr_length;
+ _PyASCIIObject_CAST(op)->length :
+ _PyCompactUnicodeObject_CAST(op)->wstr_length;
}
#define PyUnicode_WSTR_LENGTH(op) PyUnicode_WSTR_LENGTH(_PyObject_CAST(op))
diff --git a/Include/unicodeobject.h b/Include/unicodeobject.h
index 6426c5d06b445..1d2f54608544e 100644
--- a/Include/unicodeobject.h
+++ b/Include/unicodeobject.h
@@ -112,7 +112,7 @@ PyAPI_DATA(PyTypeObject) PyUnicode_Type;
PyAPI_DATA(PyTypeObject) PyUnicodeIter_Type;
#define PyUnicode_Check(op) \
- PyType_FastSubclass(Py_TYPE(op), Py_TPFLAGS_UNICODE_SUBCLASS)
+ PyType_FastSubclass(Py_TYPE(op), Py_TPFLAGS_UNICODE_SUBCLASS)
#define PyUnicode_CheckExact(op) Py_IS_TYPE(op, &PyUnicode_Type)
/* --- Constants ---------------------------------------------------------- */
diff --git a/Modules/_collectionsmodule.c b/Modules/_collectionsmodule.c
index e7bd8bc15122f..b47f977731758 100644
--- a/Modules/_collectionsmodule.c
+++ b/Modules/_collectionsmodule.c
@@ -2352,7 +2352,7 @@ _collections__count_elements_impl(PyObject *module, PyObject *mapping,
break;
if (!PyUnicode_CheckExact(key) ||
- (hash = ((PyASCIIObject *) key)->hash) == -1)
+ (hash = _PyASCIIObject_CAST(key)->hash) == -1)
{
hash = PyObject_Hash(key);
if (hash == -1)
diff --git a/Objects/dictobject.c b/Objects/dictobject.c
index 635a738985c01..88addfda8f239 100644
--- a/Objects/dictobject.c
+++ b/Objects/dictobject.c
@@ -286,7 +286,7 @@ static inline Py_hash_t
unicode_get_hash(PyObject *o)
{
assert(PyUnicode_CheckExact(o));
- return ((PyASCIIObject*)o)->hash;
+ return _PyASCIIObject_CAST(o)->hash;
}
/* Print summary info about the state of the optimized allocator */
diff --git a/Objects/setobject.c b/Objects/setobject.c
index c65b7d5d21115..022ae8e7f9392 100644
--- a/Objects/setobject.c
+++ b/Objects/setobject.c
@@ -346,7 +346,7 @@ set_add_key(PySetObject *so, PyObject *key)
Py_hash_t hash;
if (!PyUnicode_CheckExact(key) ||
- (hash = ((PyASCIIObject *) key)->hash) == -1) {
+ (hash = _PyASCIIObject_CAST(key)->hash) == -1) {
hash = PyObject_Hash(key);
if (hash == -1)
return -1;
@@ -360,7 +360,7 @@ set_contains_key(PySetObject *so, PyObject *key)
Py_hash_t hash;
if (!PyUnicode_CheckExact(key) ||
- (hash = ((PyASCIIObject *) key)->hash) == -1) {
+ (hash = _PyASCIIObject_CAST(key)->hash) == -1) {
hash = PyObject_Hash(key);
if (hash == -1)
return -1;
@@ -374,7 +374,7 @@ set_discard_key(PySetObject *so, PyObject *key)
Py_hash_t hash;
if (!PyUnicode_CheckExact(key) ||
- (hash = ((PyASCIIObject *) key)->hash) == -1) {
+ (hash = _PyASCIIObject_CAST(key)->hash) == -1) {
hash = PyObject_Hash(key);
if (hash == -1)
return -1;
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
index 4bed3ef49289a..5de8c3d2ece43 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -3759,7 +3759,7 @@ find_name_in_mro(PyTypeObject *type, PyObject *name, int *error)
{
Py_hash_t hash;
if (!PyUnicode_CheckExact(name) ||
- (hash = ((PyASCIIObject *) name)->hash) == -1)
+ (hash = _PyASCIIObject_CAST(name)->hash) == -1)
{
hash = PyObject_Hash(name);
if (hash == -1) {
@@ -3853,7 +3853,7 @@ _PyType_Lookup(PyTypeObject *type, PyObject *name)
struct type_cache_entry *entry = &cache->hashtable[h];
entry->version = type->tp_version_tag;
entry->value = res; /* borrowed */
- assert(((PyASCIIObject *)(name))->hash != -1);
+ assert(_PyASCIIObject_CAST(name)->hash != -1);
#if MCACHE_STATS
if (entry->name != Py_None && entry->name != name) {
cache->collisions++;
@@ -8951,7 +8951,7 @@ super_init_without_args(_PyInterpreterFrame *cframe, PyCodeObject *co,
if (cframe->f_lasti >= 0) {
// MAKE_CELL and COPY_FREE_VARS have no quickened forms, so no need
// to use _PyOpcode_Deopt here:
- assert(_Py_OPCODE(_PyCode_CODE(co)[0]) == MAKE_CELL ||
+ assert(_Py_OPCODE(_PyCode_CODE(co)[0]) == MAKE_CELL ||
_Py_OPCODE(_PyCode_CODE(co)[0]) == COPY_FREE_VARS);
assert(PyCell_Check(firstarg));
firstarg = PyCell_GET(firstarg);
diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c
index 72f9245afb79a..5a1d2c0630167 100644
--- a/Objects/unicodeobject.c
+++ b/Objects/unicodeobject.c
@@ -113,46 +113,46 @@ extern "C" {
#endif
#define _PyUnicode_UTF8(op) \
- (((PyCompactUnicodeObject*)(op))->utf8)
+ (_PyCompactUnicodeObject_CAST(op)->utf8)
#define PyUnicode_UTF8(op) \
(assert(_PyUnicode_CHECK(op)), \
assert(PyUnicode_IS_READY(op)), \
PyUnicode_IS_COMPACT_ASCII(op) ? \
- ((char*)((PyASCIIObject*)(op) + 1)) : \
+ ((char*)(_PyASCIIObject_CAST(op) + 1)) : \
_PyUnicode_UTF8(op))
#define _PyUnicode_UTF8_LENGTH(op) \
- (((PyCompactUnicodeObject*)(op))->utf8_length)
+ (_PyCompactUnicodeObject_CAST(op)->utf8_length)
#define PyUnicode_UTF8_LENGTH(op) \
(assert(_PyUnicode_CHECK(op)), \
assert(PyUnicode_IS_READY(op)), \
PyUnicode_IS_COMPACT_ASCII(op) ? \
- ((PyASCIIObject*)(op))->length : \
+ _PyASCIIObject_CAST(op)->length : \
_PyUnicode_UTF8_LENGTH(op))
#define _PyUnicode_WSTR(op) \
- (((PyASCIIObject*)(op))->wstr)
+ (_PyASCIIObject_CAST(op)->wstr)
/* Don't use deprecated macro of unicodeobject.h */
#undef PyUnicode_WSTR_LENGTH
#define PyUnicode_WSTR_LENGTH(op) \
- (PyUnicode_IS_COMPACT_ASCII(op) ? \
- ((PyASCIIObject*)op)->length : \
- ((PyCompactUnicodeObject*)op)->wstr_length)
+ (PyUnicode_IS_COMPACT_ASCII(op) ? \
+ _PyASCIIObject_CAST(op)->length : \
+ _PyCompactUnicodeObject_CAST(op)->wstr_length)
#define _PyUnicode_WSTR_LENGTH(op) \
- (((PyCompactUnicodeObject*)(op))->wstr_length)
+ (_PyCompactUnicodeObject_CAST(op)->wstr_length)
#define _PyUnicode_LENGTH(op) \
- (((PyASCIIObject *)(op))->length)
+ (_PyASCIIObject_CAST(op)->length)
#define _PyUnicode_STATE(op) \
- (((PyASCIIObject *)(op))->state)
+ (_PyASCIIObject_CAST(op)->state)
#define _PyUnicode_HASH(op) \
- (((PyASCIIObject *)(op))->hash)
+ (_PyASCIIObject_CAST(op)->hash)
#define _PyUnicode_KIND(op) \
(assert(_PyUnicode_CHECK(op)), \
- ((PyASCIIObject *)(op))->state.kind)
+ _PyASCIIObject_CAST(op)->state.kind)
#define _PyUnicode_GET_LENGTH(op) \
(assert(_PyUnicode_CHECK(op)), \
- ((PyASCIIObject *)(op))->length)
+ _PyASCIIObject_CAST(op)->length)
#define _PyUnicode_DATA_ANY(op) \
- (((PyUnicodeObject*)(op))->data.any)
+ (_PyUnicodeObject_CAST(op)->data.any)
#undef PyUnicode_READY
#define PyUnicode_READY(op) \
@@ -190,7 +190,7 @@ extern "C" {
buffer where the result characters are written to. */
#define _PyUnicode_CONVERT_BYTES(from_type, to_type, begin, end, to) \
do { \
- to_type *_to = (to_type *)(to); \
+ to_type *_to = (to_type *)(to); \
const from_type *_iter = (const from_type *)(begin);\
const from_type *_end = (const from_type *)(end);\
Py_ssize_t n = (_end) - (_iter); \
@@ -509,21 +509,18 @@ _PyUnicode_CheckConsistency(PyObject *op, int check_content)
#define CHECK(expr) \
do { if (!(expr)) { _PyObject_ASSERT_FAILED_MSG(op, Py_STRINGIFY(expr)); } } while (0)
- PyASCIIObject *ascii;
- unsigned int kind;
-
assert(op != NULL);
CHECK(PyUnicode_Check(op));
- ascii = (PyASCIIObject *)op;
- kind = ascii->state.kind;
+ PyASCIIObject *ascii = _PyASCIIObject_CAST(op);
+ unsigned int kind = ascii->state.kind;
if (ascii->state.ascii == 1 && ascii->state.compact == 1) {
CHECK(kind == PyUnicode_1BYTE_KIND);
CHECK(ascii->state.ready == 1);
}
else {
- PyCompactUnicodeObject *compact = (PyCompactUnicodeObject *)op;
+ PyCompactUnicodeObject *compact = _PyCompactUnicodeObject_CAST(op);
void *data;
if (ascii->state.compact == 1) {
@@ -536,7 +533,7 @@ _PyUnicode_CheckConsistency(PyObject *op, int check_content)
CHECK(compact->utf8 != data);
}
else {
- PyUnicodeObject *unicode = (PyUnicodeObject *)op;
+ PyUnicodeObject *unicode = _PyUnicodeObject_CAST(op);
data = unicode->data.any;
if (kind == PyUnicode_WCHAR_KIND) {
@@ -1330,8 +1327,8 @@ const void *_PyUnicode_data(void *unicode_raw) {
printf("obj %p\n", (void*)unicode);
printf("compact %d\n", PyUnicode_IS_COMPACT(unicode));
printf("compact ascii %d\n", PyUnicode_IS_COMPACT_ASCII(unicode));
- printf("ascii op %p\n", ((void*)((PyASCIIObject*)(unicode) + 1)));
- printf("compact op %p\n", ((void*)((PyCompactUnicodeObject*)(unicode) + 1)));
+ printf("ascii op %p\n", (void*)(_PyASCIIObject_CAST(unicode) + 1));
+ printf("compact op %p\n", (void*)(_PyCompactUnicodeObject_CAST(unicode) + 1));
printf("compact data %p\n", _PyUnicode_COMPACT_DATA(unicode));
return PyUnicode_DATA(unicode);
}
@@ -1339,9 +1336,9 @@ const void *_PyUnicode_data(void *unicode_raw) {
void
_PyUnicode_Dump(PyObject *op)
{
- PyASCIIObject *ascii = (PyASCIIObject *)op;
- PyCompactUnicodeObject *compact = (PyCompactUnicodeObject *)op;
- PyUnicodeObject *unicode = (PyUnicodeObject *)op;
+ PyASCIIObject *ascii = _PyASCIIObject_CAST(op);
+ PyCompactUnicodeObject *compact = _PyCompactUnicodeObject_CAST(op);
+ PyUnicodeObject *unicode = _PyUnicodeObject_CAST(op);
const void *data;
if (ascii->state.compact)
@@ -1976,7 +1973,7 @@ unicode_is_singleton(PyObject *unicode)
return 1;
}
- PyASCIIObject *ascii = (PyASCIIObject *)unicode;
+ PyASCIIObject *ascii = _PyASCIIObject_CAST(unicode);
if (ascii->state.kind != PyUnicode_WCHAR_KIND && ascii->length == 1) {
Py_UCS4 ch = PyUnicode_READ_CHAR(unicode, 0);
if (ch < 256 && LATIN1(ch) == unicode) {
@@ -16053,7 +16050,7 @@ _PyUnicode_FiniTypes(PyInterpreterState *interp)
static void unicode_static_dealloc(PyObject *op)
{
- PyASCIIObject* ascii = (PyASCIIObject*)op;
+ PyASCIIObject *ascii = _PyASCIIObject_CAST(op);
assert(ascii->state.compact);
diff --git a/Python/traceback.c b/Python/traceback.c
index 6a721cf909757..f5c1849101a21 100644
--- a/Python/traceback.c
+++ b/Python/traceback.c
@@ -1073,7 +1073,7 @@ _Py_DumpHexadecimal(int fd, uintptr_t value, Py_ssize_t width)
void
_Py_DumpASCII(int fd, PyObject *text)
{
- PyASCIIObject *ascii = (PyASCIIObject *)text;
+ PyASCIIObject *ascii = _PyASCIIObject_CAST(text);
Py_ssize_t i, size;
int truncated;
int kind;
@@ -1087,19 +1087,19 @@ _Py_DumpASCII(int fd, PyObject *text)
size = ascii->length;
kind = ascii->state.kind;
if (kind == PyUnicode_WCHAR_KIND) {
- wstr = ((PyASCIIObject *)text)->wstr;
+ wstr = ascii->wstr;
if (wstr == NULL)
return;
- size = ((PyCompactUnicodeObject *)text)->wstr_length;
+ size = _PyCompactUnicodeObject_CAST(text)->wstr_length;
}
else if (ascii->state.compact) {
if (ascii->state.ascii)
- data = ((PyASCIIObject*)text) + 1;
+ data = ascii + 1;
else
- data = ((PyCompactUnicodeObject*)text) + 1;
+ data = _PyCompactUnicodeObject_CAST(text) + 1;
}
else {
- data = ((PyUnicodeObject *)text)->data.any;
+ data = _PyUnicodeObject_CAST(text)->data.any;
if (data == NULL)
return;
}
1
0
bpo-46775: OSError should call winerror_to_errno unconditionally on Windows (GH-32179)
by miss-islington 31 Mar '22
by miss-islington 31 Mar '22
31 Mar '22
https://github.com/python/cpython/commit/d04a21344ae69c66f5a6df69ee6fa6988a…
commit: d04a21344ae69c66f5a6df69ee6fa6988a69b89d
branch: 3.9
author: Miss Islington (bot) <31488909+miss-islington(a)users.noreply.github.com>
committer: miss-islington <31488909+miss-islington(a)users.noreply.github.com>
date: 2022-03-30T18:49:40-07:00
summary:
bpo-46775: OSError should call winerror_to_errno unconditionally on Windows (GH-32179)
(cherry picked from commit d0c67ea0645b7ad37b867c167882a346a24de641)
Co-authored-by: Dong-hee Na <donghee.na(a)python.org>
files:
A Misc/NEWS.d/next/Core and Builtins/2022-03-30-02-36-25.bpo-46775.e3Oxqf.rst
M Objects/exceptions.c
diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-03-30-02-36-25.bpo-46775.e3Oxqf.rst b/Misc/NEWS.d/next/Core and Builtins/2022-03-30-02-36-25.bpo-46775.e3Oxqf.rst
new file mode 100644
index 0000000000000..da56ecd89367b
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2022-03-30-02-36-25.bpo-46775.e3Oxqf.rst
@@ -0,0 +1,3 @@
+Some Windows system error codes(>= 10000) are now mapped into
+the correct errno and may now raise a subclass of :exc:`OSError`.
+Patch by Dong-hee Na.
diff --git a/Objects/exceptions.c b/Objects/exceptions.c
index e67ecfab858fb..57ddbb0012134 100644
--- a/Objects/exceptions.c
+++ b/Objects/exceptions.c
@@ -844,14 +844,7 @@ oserror_parse_args(PyObject **p_args,
winerrcode = PyLong_AsLong(*winerror);
if (winerrcode == -1 && PyErr_Occurred())
return -1;
- /* Set errno to the corresponding POSIX errno (overriding
- first argument). Windows Socket error codes (>= 10000)
- have the same value as their POSIX counterparts.
- */
- if (winerrcode < 10000)
- errcode = winerror_to_errno(winerrcode);
- else
- errcode = winerrcode;
+ errcode = winerror_to_errno(winerrcode);
*myerrno = PyLong_FromLong(errcode);
if (!*myerrno)
return -1;
1
0
bpo-46775: OSError should call winerror_to_errno unconditionally on Windows (GH-32179)
by miss-islington 31 Mar '22
by miss-islington 31 Mar '22
31 Mar '22
https://github.com/python/cpython/commit/1f2ec4cef1804cda9d2df99a318373b298…
commit: 1f2ec4cef1804cda9d2df99a318373b2982919e9
branch: 3.10
author: Miss Islington (bot) <31488909+miss-islington(a)users.noreply.github.com>
committer: miss-islington <31488909+miss-islington(a)users.noreply.github.com>
date: 2022-03-30T18:48:31-07:00
summary:
bpo-46775: OSError should call winerror_to_errno unconditionally on Windows (GH-32179)
(cherry picked from commit d0c67ea0645b7ad37b867c167882a346a24de641)
Co-authored-by: Dong-hee Na <donghee.na(a)python.org>
files:
A Misc/NEWS.d/next/Core and Builtins/2022-03-30-02-36-25.bpo-46775.e3Oxqf.rst
M Objects/exceptions.c
diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-03-30-02-36-25.bpo-46775.e3Oxqf.rst b/Misc/NEWS.d/next/Core and Builtins/2022-03-30-02-36-25.bpo-46775.e3Oxqf.rst
new file mode 100644
index 0000000000000..da56ecd89367b
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2022-03-30-02-36-25.bpo-46775.e3Oxqf.rst
@@ -0,0 +1,3 @@
+Some Windows system error codes(>= 10000) are now mapped into
+the correct errno and may now raise a subclass of :exc:`OSError`.
+Patch by Dong-hee Na.
diff --git a/Objects/exceptions.c b/Objects/exceptions.c
index 6537a7ccd1e3c..9639b4436a078 100644
--- a/Objects/exceptions.c
+++ b/Objects/exceptions.c
@@ -847,14 +847,7 @@ oserror_parse_args(PyObject **p_args,
winerrcode = PyLong_AsLong(*winerror);
if (winerrcode == -1 && PyErr_Occurred())
return -1;
- /* Set errno to the corresponding POSIX errno (overriding
- first argument). Windows Socket error codes (>= 10000)
- have the same value as their POSIX counterparts.
- */
- if (winerrcode < 10000)
- errcode = winerror_to_errno(winerrcode);
- else
- errcode = winerrcode;
+ errcode = winerror_to_errno(winerrcode);
*myerrno = PyLong_FromLong(errcode);
if (!*myerrno)
return -1;
1
0
https://github.com/python/cpython/commit/db4dada5108dd49ebca23e4559a53630a2…
commit: db4dada5108dd49ebca23e4559a53630a2df8447
branch: main
author: Eric Snow <ericsnowcurrently(a)gmail.com>
committer: ericsnowcurrently <ericsnowcurrently(a)gmail.com>
date: 2022-03-30T19:24:02-06:00
summary:
bpo-47146: Avoid Using make Recursively (gh-32206)
https://bugs.python.org/issue47146
files:
M Makefile.pre.in
M Tools/scripts/generate_global_objects.py
diff --git a/Makefile.pre.in b/Makefile.pre.in
index e6c6a6ba53a6d..8d335a7e139fc 100644
--- a/Makefile.pre.in
+++ b/Makefile.pre.in
@@ -1136,10 +1136,7 @@ regen-frozen: Tools/scripts/freeze_modules.py $(FROZEN_FILES_IN)
# Deepfreeze targets
.PHONY: regen-deepfreeze
-regen-deepfreeze:
- @# Possibly generate globals first, to make sure _bootstrap_python builds.
- $(PYTHON_FOR_REGEN) $(srcdir)/Tools/scripts/generate_global_objects.py
- $(MAKE) $(DEEPFREEZE_OBJS)
+regen-deepfreeze: $(DEEPFREEZE_OBJS)
DEEPFREEZE_DEPS=$(srcdir)/Tools/scripts/deepfreeze.py $(FREEZE_MODULE_DEPS) $(FROZEN_FILES_OUT)
@@ -1180,13 +1177,25 @@ regen-importlib: regen-frozen
############################################################################
# Global objects
-.PHONY: regen-global-objects
-regen-global-objects: regen-deepfreeze
- @# We already ran in once, before deepfreezing, to make sure
- @# _bootstrap_python builds. Now we run it again to catch any
- @# remaining globals, including those added by deepfreeze.
+GLOBAL_OBJECTS_TARGETS = \
+ $(srcdir)/Include/internal/pycore_global_objects.h \
+ $(srcdir)/Include/internal/pycore_global_strings.h
+
+# The global objects will get regenerated as soon these files
+# are required, including as a prerequisite for regen-deepfreeze.
+$(GLOBAL_OBJECTS_TARGETS): generate-global-objects
+
+.PHONY: generate-global-objects
+generate-global-objects: $(srcdir)/Tools/scripts/generate_global_objects.py
$(PYTHON_FOR_REGEN) $(srcdir)/Tools/scripts/generate_global_objects.py
+.PHONY: generate-global-objects-after-deepfreeze
+generate-global-objects-after-deepfreeze: regen-deepfreeze $(srcdir)/Tools/scripts/generate_global_objects.py
+ $(PYTHON_FOR_REGEN) $(srcdir)/Tools/scripts/generate_global_objects.py
+
+.PHONY: regen-global-objects
+regen-global-objects: regen-deepfreeze generate-global-objects-after-deepfreeze
+
############################################################################
# ABI
diff --git a/Tools/scripts/generate_global_objects.py b/Tools/scripts/generate_global_objects.py
index f7653604e822b..826f4c4c83aec 100644
--- a/Tools/scripts/generate_global_objects.py
+++ b/Tools/scripts/generate_global_objects.py
@@ -115,7 +115,12 @@ def iter_global_strings():
id_regex = re.compile(r'\b_Py_ID\((\w+)\)')
str_regex = re.compile(r'\b_Py_DECLARE_STR\((\w+), "(.*?)"\)')
for filename in iter_files():
- with open(filename, encoding='utf-8') as infile:
+ try:
+ infile = open(filename, encoding='utf-8')
+ except FileNotFoundError:
+ # The file must have been a temporary file.
+ continue
+ with infile:
for lno, line in enumerate(infile, 1):
for m in id_regex.finditer(line):
identifier, = m.groups()
1
0
30 Mar '22
https://github.com/python/cpython/commit/f3d5715492195fd2532fc1a5d73be07923…
commit: f3d5715492195fd2532fc1a5d73be07923cdf2e1
branch: main
author: Steve Dower <steve.dower(a)python.org>
committer: zooba <steve.dower(a)microsoft.com>
date: 2022-03-30T22:18:40+01:00
summary:
bpo-46566: Make test_launcher more robust to a variety of installs (GH-32204)
files:
M Lib/test/test_launcher.py
diff --git a/Lib/test/test_launcher.py b/Lib/test/test_launcher.py
index 2fb5aae628a67..52b1cfa212b88 100644
--- a/Lib/test/test_launcher.py
+++ b/Lib/test/test_launcher.py
@@ -151,6 +151,30 @@ def find_py(cls):
py_exe = Path(p) / PY_EXE
if py_exe.is_file():
break
+ else:
+ py_exe = None
+
+ # Test launch and check version, to exclude installs of older
+ # releases when running outside of a source tree
+ if py_exe:
+ try:
+ with subprocess.Popen(
+ [py_exe, "-h"],
+ stdin=subprocess.PIPE,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ encoding="ascii",
+ errors="ignore",
+ ) as p:
+ p.stdin.close()
+ version = next(p.stdout).splitlines()[0].rpartition(" ")[2]
+ p.stdout.read()
+ p.wait(10)
+ if not sys.version.startswith(version):
+ py_exe = None
+ except OSError:
+ py_exe = None
+
if not py_exe:
raise unittest.SkipTest(
"cannot locate '{}' for test".format(PY_EXE)
@@ -162,6 +186,7 @@ def run_py(self, args, env=None, allow_fail=False, expect_returncode=0):
self.py_exe = self.find_py()
env = {**os.environ, **(env or {}), "PYLAUNCHER_DEBUG": "1", "PYLAUNCHER_DRYRUN": "1"}
+ env.pop("VIRTUAL_ENV", None)
with subprocess.Popen(
[self.py_exe, *args],
env=env,
@@ -216,7 +241,7 @@ def setUpClass(cls):
if support.verbose:
p = subprocess.check_output("reg query HKCU\\Software\\Python /s")
- print(p.decode('mbcs'))
+ #print(p.decode('mbcs'))
@classmethod
@@ -251,9 +276,9 @@ def test_list(self):
found = {}
expect = {}
for line in data["stdout"].splitlines():
- m = re.match(r"\s*(.+?)\s+(.+)$", line)
+ m = re.match(r"\s*(.+?)\s+?(\*\s+)?(.+)$", line)
if m:
- found[m.group(1)] = m.group(2)
+ found[m.group(1)] = m.group(3)
for company in TEST_DATA:
company_data = TEST_DATA[company]
tags = [t for t in company_data if isinstance(company_data[t], dict)]
@@ -276,9 +301,9 @@ def test_list_paths(self):
found = {}
expect = {}
for line in data["stdout"].splitlines():
- m = re.match(r"\s*(.+?)\s+(.+)$", line)
+ m = re.match(r"\s*(.+?)\s+?(\*\s+)?(.+)$", line)
if m:
- found[m.group(1)] = m.group(2)
+ found[m.group(1)] = m.group(3)
for company in TEST_DATA:
company_data = TEST_DATA[company]
tags = [t for t in company_data if isinstance(company_data[t], dict)]
@@ -415,9 +440,10 @@ def test_install(self):
# If winget is runnable, we should find it. Otherwise, we'll be trying
# to open the Store.
try:
- subprocess.check_call(["winget.exe", "--version"])
+ subprocess.check_call(["winget.exe", "--version"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
except FileNotFoundError:
self.assertIn("ms-windows-store://", cmd)
else:
self.assertIn("winget.exe", cmd)
+ # Both command lines include the store ID
self.assertIn("9PJPW5LDXLZ5", cmd)
1
0
30 Mar '22
https://github.com/python/cpython/commit/2ab609dd614045f3b112ede0b0883339de…
commit: 2ab609dd614045f3b112ede0b0883339de784f2a
branch: main
author: Steve Dower <steve.dower(a)python.org>
committer: zooba <steve.dower(a)microsoft.com>
date: 2022-03-30T21:20:38+01:00
summary:
bpo-47171: Enable installing the py.exe launcher on Windows ARM64 (GH-32203)
files:
A Misc/NEWS.d/next/Windows/2022-03-30-19-55-00.bpo-47171.MbqCWn.rst
M Tools/msi/bundle/Default.ARM64.xsl
M Tools/msi/bundle/bundle.wxs
M Tools/msi/exe/exe.wixproj
diff --git a/Misc/NEWS.d/next/Windows/2022-03-30-19-55-00.bpo-47171.MbqCWn.rst b/Misc/NEWS.d/next/Windows/2022-03-30-19-55-00.bpo-47171.MbqCWn.rst
new file mode 100644
index 0000000000000..d9f1795f1e1f7
--- /dev/null
+++ b/Misc/NEWS.d/next/Windows/2022-03-30-19-55-00.bpo-47171.MbqCWn.rst
@@ -0,0 +1 @@
+Enables installing the :file:`py.exe` launcher on Windows ARM64.
diff --git a/Tools/msi/bundle/Default.ARM64.xsl b/Tools/msi/bundle/Default.ARM64.xsl
index f63da4e7274cb..b28b3f264adbc 100644
--- a/Tools/msi/bundle/Default.ARM64.xsl
+++ b/Tools/msi/bundle/Default.ARM64.xsl
@@ -10,6 +10,10 @@
</xsl:copy>
</xsl:template>
+ <!--
+ ** No longer need this change, but I'm leaving the snippets here as an example
+ ** in case we need to add another override in the future.
+
<xsl:template match="*[local-name()='String' and @Id='InstallButtonNote']">
<String Id="InstallButtonNote">[TargetDir]
@@ -20,4 +24,5 @@ Creates shortcuts but no file associations</String>
<xsl:template match="*[local-name()='String' and @Id='Include_launcherHelp']">
<String Id="Include_launcherHelp">(The 'py' launcher is currently unavailable on ARM64.)</String>
</xsl:template>
+ -->
</xsl:stylesheet>
\ No newline at end of file
diff --git a/Tools/msi/bundle/bundle.wxs b/Tools/msi/bundle/bundle.wxs
index ac4b7a6d75308..19e67faf887bc 100644
--- a/Tools/msi/bundle/bundle.wxs
+++ b/Tools/msi/bundle/bundle.wxs
@@ -56,9 +56,7 @@
<Variable Name="DefaultCustomTargetDir" Value="" bal:Overridable="yes" />
<Variable Name="InstallAllUsersState" Value="enabled" bal:Overridable="yes" />
- <?if "$(var.Platform)"~="ARM64" ?>
- <Variable Name="InstallLauncherAllUsersState" Value="hide" bal:Overridable="yes" />
- <?elseif "$(var.PyTestExt)"="" ?>
+ <?if "$(var.PyTestExt)"="" ?>
<Variable Name="InstallLauncherAllUsersState" Value="enabled" bal:Overridable="yes" />
<?else ?>
<Variable Name="InstallLauncherAllUsersState" Value="disable" bal:Overridable="yes" />
@@ -76,17 +74,12 @@
<Variable Name="Include_tools" Value="1" bal:Overridable="yes" />
<Variable Name="Include_tcltk" Value="1" bal:Overridable="yes" />
<Variable Name="Include_pip" Value="1" bal:Overridable="yes" />
- <?if $(var.Platform)~="ARM64" ?>
- <Variable Name="Include_launcher" Value="0" bal:Overridable="yes" />
- <Variable Name="Include_launcherState" Value="disable" />
- <?else ?>
<Variable Name="Include_launcher" Value="-1" bal:Overridable="yes" />
<?if "$(var.PyTestExt)"="" ?>
<Variable Name="Include_launcherState" Value="enabled" bal:Overridable="yes" />
<?else ?>
<Variable Name="Include_launcherState" Value="disable" />
<?endif ?>
- <?endif ?>
<Variable Name="Include_symbols" Value="0" bal:Overridable="yes" />
<Variable Name="Include_debug" Value="0" bal:Overridable="yes" />
@@ -115,9 +108,7 @@
<PackageGroupRef Id="doc" />
<PackageGroupRef Id="tools" />
<PackageGroupRef Id="tcltk" />
- <?if $(var.Platform)!="ARM64" ?>
<PackageGroupRef Id="launcher" />
- <?endif ?>
<PackageGroupRef Id="pip" />
<PackageGroupRef Id="packageinstall" />
<PackageGroupRef Id="postinstall" />
diff --git a/Tools/msi/exe/exe.wixproj b/Tools/msi/exe/exe.wixproj
index be44f442f7c9d..592c8d2f65ae6 100644
--- a/Tools/msi/exe/exe.wixproj
+++ b/Tools/msi/exe/exe.wixproj
@@ -32,18 +32,9 @@
<Exec Command="$(Blurb) merge -f "$(BuildPath)NEWS.txt"" WorkingDirectory="$(PCbuild)" />
</Target>
- <Target Name="_MergeMiscNewsWithPython" AfterTargets="PrepareForBuild" Condition="$(Blurb) == '' and !Exists('$(PySourcePath)Misc\NEWS')">
- <ItemGroup>
- <HostPython Include="$(ExternalsDir)python*\tools\python.exe" />
- <HostPython Include="@(HostPython)" Condition="Exists(%(FullPath))" />
- <HostPython Include="py" Condition="@(HostPython) == ''" />
- </ItemGroup>
- <PropertyGroup>
- <HostPython>@(HostPython)</HostPython>
- <HostPython Condition="$(HostPython.Contains(';'))">$(HostPython.Remove($(HostPython.IndexOf(';'))))</HostPython>
- </PropertyGroup>
- <Exec Command=""$(HostPython)" -m pip install -U blurb" WorkingDirectory="$(PCbuild)" />
- <Exec Command=""$(HostPython)" -m blurb merge -f "$(BuildPath)NEWS.txt"" WorkingDirectory="$(PCbuild)" />
+ <Target Name="_MergeMiscNewsWithPython" AfterTargets="PrepareForBuild" Condition="$(Blurb) == '' and !Exists('$(PySourcePath)Misc\NEWS')" DependsOnTargets="FindPythonForBuild">
+ <Exec Command="$(PythonForBuild) -m pip install -U blurb" WorkingDirectory="$(PCbuild)" />
+ <Exec Command="$(PythonForBuild) -m blurb merge -f "$(BuildPath)NEWS.txt"" WorkingDirectory="$(PCbuild)" />
</Target>
<Import Project="..\msi.targets" />
1
0