Skip to content

Commit 20bf23b

Browse files
authored
Merge branch 'main' into exc-handler-context
2 parents 28ac42b + 670007a commit 20bf23b

39 files changed

+756
-516
lines changed

Doc/c-api/function.rst

+9
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,15 @@ There are a few functions specific to Python functions.
8383
Raises :exc:`SystemError` and returns ``-1`` on failure.
8484
8585
86+
.. c:function:: void PyFunction_SetVectorcall(PyFunctionObject *func, vectorcallfunc vectorcall)
87+
88+
Set the vectorcall field of a given function object *func*.
89+
90+
Warning: extensions using this API must preserve the behavior
91+
of the unaltered (default) vectorcall function!
92+
93+
.. versionadded:: 3.12
94+
8695
.. c:function:: PyObject* PyFunction_GetClosure(PyObject *op)
8796
8897
Return the closure associated with the function object *op*. This can be ``NULL``

Doc/library/itertools.rst

+7-1
Original file line numberDiff line numberDiff line change
@@ -818,7 +818,7 @@ which incur interpreter overhead.
818818
data = bytearray([1]) * n
819819
data[:2] = 0, 0
820820
limit = math.isqrt(n) + 1
821-
for p in compress(count(), islice(data, limit)):
821+
for p in compress(range(limit), data):
822822
data[p+p : n : p] = bytearray(len(range(p+p, n, p)))
823823
return compress(count(), data)
824824

@@ -1168,6 +1168,9 @@ which incur interpreter overhead.
11681168

11691169
>>> list(sieve(30))
11701170
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
1171+
>>> small_primes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59]
1172+
>>> all(list(sieve(n)) == [p for p in small_primes if p < n] for n in range(60))
1173+
True
11711174
>>> len(list(sieve(100)))
11721175
25
11731176
>>> len(list(sieve(1_000)))
@@ -1178,6 +1181,9 @@ which incur interpreter overhead.
11781181
9592
11791182
>>> len(list(sieve(1_000_000)))
11801183
78498
1184+
>>> carmichael = {561, 1105, 1729, 2465, 2821, 6601, 8911} # https://oeis.org/A002997
1185+
>>> set(sieve(10_000)).isdisjoint(carmichael)
1186+
True
11811187

11821188
>>> list(flatten([('a', 'b'), (), ('c', 'd', 'e'), ('f',), ('g', 'h', 'i')]))
11831189
['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i']

Doc/library/math.rst

+2-2
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,8 @@ Number-theoretic and representation functions
4545
to zero when ``k > n``.
4646

4747
Also called the binomial coefficient because it is equivalent
48-
to the coefficient of k-th term in polynomial expansion of the
49-
expression ``(1 + x) ** n``.
48+
to the coefficient of k-th term in polynomial expansion of
49+
``(1 + x)``.
5050

5151
Raises :exc:`TypeError` if either of the arguments are not integers.
5252
Raises :exc:`ValueError` if either of the arguments are negative.

Doc/library/sqlite3.rst

+2-1
Original file line numberDiff line numberDiff line change
@@ -2274,7 +2274,8 @@ If the connection attribute :attr:`~Connection.isolation_level`
22742274
is not ``None``,
22752275
new transactions are implicitly opened before
22762276
:meth:`~Cursor.execute` and :meth:`~Cursor.executemany` executes
2277-
``INSERT``, ``UPDATE``, ``DELETE``, or ``REPLACE`` statements.
2277+
``INSERT``, ``UPDATE``, ``DELETE``, or ``REPLACE`` statements;
2278+
for other statements, no implicit transaction handling is performed.
22782279
Use the :meth:`~Connection.commit` and :meth:`~Connection.rollback` methods
22792280
to respectively commit and roll back pending transactions.
22802281
You can choose the underlying `SQLite transaction behaviour`_ —

Doc/library/stdtypes.rst

+2-2
Original file line numberDiff line numberDiff line change
@@ -5493,15 +5493,15 @@ When an operation would exceed the limit, a :exc:`ValueError` is raised:
54935493
>>> _ = int('2' * 5432)
54945494
Traceback (most recent call last):
54955495
...
5496-
ValueError: Exceeds the limit (4300) for integer string conversion: value has 5432 digits.
5496+
ValueError: Exceeds the limit (4300) for integer string conversion: value has 5432 digits; use sys.set_int_max_str_digits() to increase the limit.
54975497
>>> i = int('2' * 4300)
54985498
>>> len(str(i))
54995499
4300
55005500
>>> i_squared = i*i
55015501
>>> len(str(i_squared))
55025502
Traceback (most recent call last):
55035503
...
5504-
ValueError: Exceeds the limit (4300) for integer string conversion: value has 8599 digits.
5504+
ValueError: Exceeds the limit (4300) for integer string conversion: value has 8599 digits; use sys.set_int_max_str_digits() to increase the limit.
55055505
>>> len(hex(i_squared))
55065506
7144
55075507
>>> assert int(hex(i_squared), base=16) == i*i # Hexadecimal is unlimited.

Doc/using/configure.rst

+3
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,9 @@ also be used to improve performance.
232232
.. versionadded:: 3.11
233233
To use ThinLTO feature, use ``--with-lto=thin`` on Clang.
234234

235+
.. versionchanged:: 3.12
236+
Use ThinLTO as the default optimization policy on Clang if the compiler accepts the flag.
237+
235238
.. cmdoption:: --enable-bolt
236239

237240
Enable usage of the `BOLT post-link binary optimizer

Doc/whatsnew/3.12.rst

+10-2
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,8 @@
4343
module.
4444
(Contributed by P.Y. Developer in :issue:`12345`.)
4545
46-
This saves the maintainer the effort of going through the Mercurial log
47-
when researching a change.
46+
This saves the maintainer the effort of going through the VCS log when
47+
researching a change.
4848
4949
This article explains the new features in Python 3.12, compared to 3.11.
5050

@@ -453,6 +453,10 @@ Build Changes
453453
``va_start()`` is no longer called with a single parameter.
454454
(Contributed by Kumar Aditya in :gh:`93207`.)
455455

456+
* CPython now uses the ThinLTO option as the default link time optimization policy
457+
if the Clang compiler accepts the flag.
458+
(Contributed by Dong-hee Na in :gh:`89536`.)
459+
456460

457461
C API Changes
458462
=============
@@ -493,6 +497,10 @@ New Features
493497
functions in all running threads in addition to the calling one. (Contributed
494498
by Pablo Galindo in :gh:`93503`.)
495499

500+
* Added new function :c:func:`PyFunction_SetVectorcall` to the C API
501+
which sets the vectorcall field of a given :c:type:`PyFunctionObject`.
502+
(Contributed by Andrew Frost in :gh:`92257`.)
503+
496504
Porting to Python 3.12
497505
----------------------
498506

Grammar/python.gram

+8-8
Original file line numberDiff line numberDiff line change
@@ -1162,14 +1162,14 @@ invalid_dict_comprehension:
11621162
| '{' a='**' bitwise_or for_if_clauses '}' {
11631163
RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "dict unpacking cannot be used in dict comprehension") }
11641164
invalid_parameters:
1165-
| param_no_default* invalid_parameters_helper a=param_no_default {
1166-
RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "non-default argument follows default argument") }
1167-
| param_no_default* a='(' param_no_default+ ','? b=')' {
1168-
RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, b, "Function parameters cannot be parenthesized") }
11691165
| a="/" ',' {
11701166
RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "at least one argument must precede /") }
11711167
| (slash_no_default | slash_with_default) param_maybe_default* a='/' {
11721168
RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "/ may appear only once") }
1169+
| slash_no_default? param_no_default* invalid_parameters_helper a=param_no_default {
1170+
RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "parameter without a default follows parameter with a default") }
1171+
| param_no_default* a='(' param_no_default+ ','? b=')' {
1172+
RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, b, "Function parameters cannot be parenthesized") }
11731173
| (slash_no_default | slash_with_default)? param_maybe_default* '*' (',' | param_no_default) param_maybe_default* a='/' {
11741174
RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "/ must be ahead of *") }
11751175
| param_maybe_default+ '/' a='*' {
@@ -1190,14 +1190,14 @@ invalid_parameters_helper: # This is only there to avoid type errors
11901190
| a=slash_with_default { _PyPegen_singleton_seq(p, a) }
11911191
| param_with_default+
11921192
invalid_lambda_parameters:
1193-
| lambda_param_no_default* invalid_lambda_parameters_helper a=lambda_param_no_default {
1194-
RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "non-default argument follows default argument") }
1195-
| lambda_param_no_default* a='(' ','.lambda_param+ ','? b=')' {
1196-
RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, b, "Lambda expression parameters cannot be parenthesized") }
11971193
| a="/" ',' {
11981194
RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "at least one argument must precede /") }
11991195
| (lambda_slash_no_default | lambda_slash_with_default) lambda_param_maybe_default* a='/' {
12001196
RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "/ may appear only once") }
1197+
| lambda_slash_no_default? lambda_param_no_default* invalid_lambda_parameters_helper a=lambda_param_no_default {
1198+
RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "parameter without a default follows parameter with a default") }
1199+
| lambda_param_no_default* a='(' ','.lambda_param+ ','? b=')' {
1200+
RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, b, "Lambda expression parameters cannot be parenthesized") }
12011201
| (lambda_slash_no_default | lambda_slash_with_default)? lambda_param_maybe_default* '*' (',' | lambda_param_no_default) lambda_param_maybe_default* a='/' {
12021202
RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "/ must be ahead of *") }
12031203
| lambda_param_maybe_default+ '/' a='*' {

Include/cpython/funcobject.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,8 @@ typedef struct {
4848
* defaults
4949
* kwdefaults (only if the object changes, not the contents of the dict)
5050
* code
51-
* annotations */
51+
* annotations
52+
* vectorcall function pointer */
5253
uint32_t func_version;
5354

5455
/* Invariant:
@@ -69,6 +70,7 @@ PyAPI_FUNC(PyObject *) PyFunction_GetGlobals(PyObject *);
6970
PyAPI_FUNC(PyObject *) PyFunction_GetModule(PyObject *);
7071
PyAPI_FUNC(PyObject *) PyFunction_GetDefaults(PyObject *);
7172
PyAPI_FUNC(int) PyFunction_SetDefaults(PyObject *, PyObject *);
73+
PyAPI_FUNC(void) PyFunction_SetVectorcall(PyFunctionObject *, vectorcallfunc);
7274
PyAPI_FUNC(PyObject *) PyFunction_GetKwDefaults(PyObject *);
7375
PyAPI_FUNC(int) PyFunction_SetKwDefaults(PyObject *, PyObject *);
7476
PyAPI_FUNC(PyObject *) PyFunction_GetClosure(PyObject *);

Include/internal/pycore_code.h

+19-74
Original file line numberDiff line numberDiff line change
@@ -285,110 +285,55 @@ PyAPI_FUNC(PyObject*) _Py_GetSpecializationStats(void);
285285
#define EVAL_CALL_STAT_INC_IF_FUNCTION(name, callable) ((void)0)
286286
#endif // !Py_STATS
287287

288-
// Cache values are only valid in memory, so use native endianness.
289-
#ifdef WORDS_BIGENDIAN
288+
// Utility functions for reading/writing 32/64-bit values in the inline caches.
289+
// Great care should be taken to ensure that these functions remain correct and
290+
// performant! They should compile to just "move" instructions on all supported
291+
// compilers and platforms.
292+
293+
// We use memcpy to let the C compiler handle unaligned accesses and endianness
294+
// issues for us. It also seems to produce better code than manual copying for
295+
// most compilers (see https://blog.regehr.org/archives/959 for more info).
290296

291297
static inline void
292298
write_u32(uint16_t *p, uint32_t val)
293299
{
294-
p[0] = (uint16_t)(val >> 16);
295-
p[1] = (uint16_t)(val >> 0);
300+
memcpy(p, &val, sizeof(val));
296301
}
297302

298303
static inline void
299304
write_u64(uint16_t *p, uint64_t val)
300305
{
301-
p[0] = (uint16_t)(val >> 48);
302-
p[1] = (uint16_t)(val >> 32);
303-
p[2] = (uint16_t)(val >> 16);
304-
p[3] = (uint16_t)(val >> 0);
305-
}
306-
307-
static inline uint32_t
308-
read_u32(uint16_t *p)
309-
{
310-
uint32_t val = 0;
311-
val |= (uint32_t)p[0] << 16;
312-
val |= (uint32_t)p[1] << 0;
313-
return val;
314-
}
315-
316-
static inline uint64_t
317-
read_u64(uint16_t *p)
318-
{
319-
uint64_t val = 0;
320-
val |= (uint64_t)p[0] << 48;
321-
val |= (uint64_t)p[1] << 32;
322-
val |= (uint64_t)p[2] << 16;
323-
val |= (uint64_t)p[3] << 0;
324-
return val;
325-
}
326-
327-
#else
328-
329-
static inline void
330-
write_u32(uint16_t *p, uint32_t val)
331-
{
332-
p[0] = (uint16_t)(val >> 0);
333-
p[1] = (uint16_t)(val >> 16);
306+
memcpy(p, &val, sizeof(val));
334307
}
335308

336309
static inline void
337-
write_u64(uint16_t *p, uint64_t val)
310+
write_obj(uint16_t *p, PyObject *val)
338311
{
339-
p[0] = (uint16_t)(val >> 0);
340-
p[1] = (uint16_t)(val >> 16);
341-
p[2] = (uint16_t)(val >> 32);
342-
p[3] = (uint16_t)(val >> 48);
312+
memcpy(p, &val, sizeof(val));
343313
}
344314

345315
static inline uint32_t
346316
read_u32(uint16_t *p)
347317
{
348-
uint32_t val = 0;
349-
val |= (uint32_t)p[0] << 0;
350-
val |= (uint32_t)p[1] << 16;
318+
uint32_t val;
319+
memcpy(&val, p, sizeof(val));
351320
return val;
352321
}
353322

354323
static inline uint64_t
355324
read_u64(uint16_t *p)
356325
{
357-
uint64_t val = 0;
358-
val |= (uint64_t)p[0] << 0;
359-
val |= (uint64_t)p[1] << 16;
360-
val |= (uint64_t)p[2] << 32;
361-
val |= (uint64_t)p[3] << 48;
326+
uint64_t val;
327+
memcpy(&val, p, sizeof(val));
362328
return val;
363329
}
364330

365-
#endif
366-
367-
static inline void
368-
write_obj(uint16_t *p, PyObject *obj)
369-
{
370-
uintptr_t val = (uintptr_t)obj;
371-
#if SIZEOF_VOID_P == 8
372-
write_u64(p, val);
373-
#elif SIZEOF_VOID_P == 4
374-
write_u32(p, val);
375-
#else
376-
#error "SIZEOF_VOID_P must be 4 or 8"
377-
#endif
378-
}
379-
380331
static inline PyObject *
381332
read_obj(uint16_t *p)
382333
{
383-
uintptr_t val;
384-
#if SIZEOF_VOID_P == 8
385-
val = read_u64(p);
386-
#elif SIZEOF_VOID_P == 4
387-
val = read_u32(p);
388-
#else
389-
#error "SIZEOF_VOID_P must be 4 or 8"
390-
#endif
391-
return (PyObject *)val;
334+
PyObject *val;
335+
memcpy(&val, p, sizeof(val));
336+
return val;
392337
}
393338

394339
/* See Objects/exception_handling_notes.txt for details.

Lib/codeop.py

+13-13
Original file line numberDiff line numberDiff line change
@@ -56,22 +56,22 @@ def _maybe_compile(compiler, source, filename, symbol):
5656
if symbol != "eval":
5757
source = "pass" # Replace it with a 'pass' statement
5858

59-
try:
60-
return compiler(source, filename, symbol)
61-
except SyntaxError: # Let other compile() errors propagate.
62-
pass
63-
64-
# Catch syntax warnings after the first compile
65-
# to emit warnings (SyntaxWarning, DeprecationWarning) at most once.
59+
# Disable compiler warnings when checking for incomplete input.
6660
with warnings.catch_warnings():
67-
warnings.simplefilter("error")
68-
61+
warnings.simplefilter("ignore", (SyntaxWarning, DeprecationWarning))
6962
try:
70-
compiler(source + "\n", filename, symbol)
71-
except SyntaxError as e:
72-
if "incomplete input" in str(e):
63+
compiler(source, filename, symbol)
64+
except SyntaxError: # Let other compile() errors propagate.
65+
try:
66+
compiler(source + "\n", filename, symbol)
7367
return None
74-
raise
68+
except SyntaxError as e:
69+
if "incomplete input" in str(e):
70+
return None
71+
# fallthrough
72+
73+
return compiler(source, filename, symbol)
74+
7575

7676
def _is_syntax_error(err1, err2):
7777
rep1 = repr(err1)

Lib/idlelib/idle_test/test_text.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from test.support import requires
77
from _tkinter import TclError
88

9-
class TextTest(object):
9+
class TextTest:
1010
"Define items common to both sets of tests."
1111

1212
hw = 'hello\nworld' # Several tests insert this after initialization.

Lib/idlelib/idle_test/test_zzdummy.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
}
2020
code_sample = """\
2121
22-
class C1():
22+
class C1:
2323
# Class comment.
2424
def __init__(self, a, b):
2525
self.a = a

Lib/pstats.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ def __new__(cls, *values):
5757

5858
@dataclass(unsafe_hash=True)
5959
class FunctionProfile:
60-
ncalls: int
60+
ncalls: str
6161
tottime: float
6262
percall_tottime: float
6363
cumtime: float

0 commit comments

Comments
 (0)