Skip to content

Commit f8fc1c5

Browse files
committed
gh-115754: Get singletons by function calls in lmited C API 3.13
In the limited C API version 3.13, getting Py_None, Py_False, Py_True, Py_Ellipsis and Py_NotImplemented singletons is now implemented as function calls at the stable ABI level to hide implementation details. Getting these constants still return borrowed references.
1 parent 729bfb3 commit f8fc1c5

File tree

9 files changed

+73
-8
lines changed

9 files changed

+73
-8
lines changed

Doc/whatsnew/3.13.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1645,6 +1645,11 @@ New Features
16451645
between native integer types and Python :class:`int` objects.
16461646
(Contributed by Steve Dower in :gh:`111140`.)
16471647

1648+
* In the limited C API version 3.13, getting ``Py_None``, ``Py_False``,
1649+
``Py_True``, ``Py_Ellipsis`` and ``Py_NotImplemented`` singletons is now
1650+
implemented as function calls at the stable ABI level to hide implementation
1651+
details. Getting these constants still return borrowed references.
1652+
(Contributed by Victor Stinner in :gh:`115754`.)
16481653

16491654
Porting to Python 3.13
16501655
----------------------

Include/boolobject.h

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,17 @@ extern "C" {
1616
/* Don't use these directly */
1717
PyAPI_DATA(PyLongObject) _Py_FalseStruct;
1818
PyAPI_DATA(PyLongObject) _Py_TrueStruct;
19+
PyAPI_FUNC(PyObject*) _Py_GetFalse(void);
20+
PyAPI_FUNC(PyObject*) _Py_GetTrue(void);
21+
22+
#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x030D0000
23+
# define Py_False _Py_GetFalse()
24+
# define Py_True _Py_GetTrue()
25+
#else
26+
# define Py_False _PyObject_CAST(&_Py_FalseStruct)
27+
# define Py_True _PyObject_CAST(&_Py_TrueStruct)
28+
#endif
1929

20-
/* Use these macros */
21-
#define Py_False _PyObject_CAST(&_Py_FalseStruct)
22-
#define Py_True _PyObject_CAST(&_Py_TrueStruct)
2330

2431
// Test if an object is the True singleton, the same as "x is True" in Python.
2532
PyAPI_FUNC(int) Py_IsTrue(PyObject *x);

Include/object.h

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1070,7 +1070,13 @@ _Py_NoneStruct is an object of undefined type which can be used in contexts
10701070
where NULL (nil) is not suitable (since NULL often means 'error').
10711071
*/
10721072
PyAPI_DATA(PyObject) _Py_NoneStruct; /* Don't use this directly */
1073-
#define Py_None (&_Py_NoneStruct)
1073+
PyAPI_FUNC(PyObject*) _Py_GetNone(void);
1074+
1075+
#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x030D0000
1076+
# define Py_None _Py_GetNone()
1077+
#else
1078+
# define Py_None (&_Py_NoneStruct)
1079+
#endif
10741080

10751081
// Test if an object is the None singleton, the same as "x is None" in Python.
10761082
PyAPI_FUNC(int) Py_IsNone(PyObject *x);
@@ -1084,7 +1090,13 @@ Py_NotImplemented is a singleton used to signal that an operation is
10841090
not implemented for a given type combination.
10851091
*/
10861092
PyAPI_DATA(PyObject) _Py_NotImplementedStruct; /* Don't use this directly */
1087-
#define Py_NotImplemented (&_Py_NotImplementedStruct)
1093+
PyAPI_FUNC(PyObject*) _Py_GetNotImplemented(void);
1094+
1095+
#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x030D0000
1096+
# define Py_NotImplemented _Py_GetNotImplemented()
1097+
#else
1098+
# define Py_NotImplemented (&_Py_NotImplementedStruct)
1099+
#endif
10881100

10891101
/* Macro for returning Py_NotImplemented from a function */
10901102
#define Py_RETURN_NOTIMPLEMENTED return Py_NotImplemented

Include/sliceobject.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,13 @@ extern "C" {
77
/* The unique ellipsis object "..." */
88

99
PyAPI_DATA(PyObject) _Py_EllipsisObject; /* Don't use this directly */
10+
PyAPI_FUNC(PyObject*) _Py_GetEllipsis(void);
1011

11-
#define Py_Ellipsis (&_Py_EllipsisObject)
12+
#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x030D0000
13+
# define Py_Ellipsis _Py_GetEllipsis()
14+
#else
15+
# define Py_Ellipsis (&_Py_EllipsisObject)
16+
#endif
1217

1318
/* Slice object interface */
1419

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
In the limited C API version 3.13, getting ``Py_None``, ``Py_False``,
2+
``Py_True``, ``Py_Ellipsis`` and ``Py_NotImplemented`` singletons is now
3+
implemented as function calls at the stable ABI level to hide implementation
4+
details. Getting these constants still return borrowed references. Patch by
5+
Victor Stinner.

Misc/stable_abi.toml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2496,3 +2496,13 @@
24962496
[typedef.PyCFunctionFastWithKeywords]
24972497
added = '3.13'
24982498
# "abi-only" since 3.10. (Same story as PyCFunctionFast.)
2499+
[typedef._Py_GetNone]
2500+
added = '3.13'
2501+
[typedef._Py_GetFalse]
2502+
added = '3.13'
2503+
[typedef._Py_GetTrue]
2504+
added = '3.13'
2505+
[typedef._Py_GetEllipsis]
2506+
added = '3.13'
2507+
[typedef._Py_GetNotImplemented]
2508+
added = '3.13'

Objects/longobject.c

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6592,16 +6592,23 @@ _PyLong_FiniTypes(PyInterpreterState *interp)
65926592
_PyStructSequence_FiniBuiltin(interp, &Int_InfoType);
65936593
}
65946594

6595-
#undef PyUnstable_Long_IsCompact
65966595

6596+
// -- Stable ABI ------------------------------------------------------------
6597+
6598+
#undef PyUnstable_Long_IsCompact
65976599
int
65986600
PyUnstable_Long_IsCompact(const PyLongObject* op) {
65996601
return _PyLong_IsCompact(op);
66006602
}
66016603

66026604
#undef PyUnstable_Long_CompactValue
6603-
66046605
Py_ssize_t
66056606
PyUnstable_Long_CompactValue(const PyLongObject* op) {
66066607
return _PyLong_CompactValue(op);
66076608
}
6609+
6610+
PyObject* _Py_GetFalse(void)
6611+
{ return _PyObject_CAST(&_Py_FalseStruct); }
6612+
6613+
PyObject* _Py_GetTrue(void)
6614+
{ return _PyObject_CAST(&_Py_TrueStruct); }

Objects/object.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2920,6 +2920,8 @@ PyObject_GET_WEAKREFS_LISTPTR(PyObject *op)
29202920
}
29212921

29222922

2923+
// -- Stable ABI ------------------------------------------------------------
2924+
29232925
#undef Py_NewRef
29242926
#undef Py_XNewRef
29252927

@@ -2970,3 +2972,9 @@ _Py_SetRefcnt(PyObject *ob, Py_ssize_t refcnt)
29702972
{
29712973
Py_SET_REFCNT(ob, refcnt);
29722974
}
2975+
2976+
PyObject* _Py_GetNone(void)
2977+
{ return &_Py_NoneStruct; }
2978+
2979+
PyObject* _Py_GetNotImplemented(void)
2980+
{ return &_Py_NotImplementedStruct; }

Objects/sliceobject.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -721,3 +721,9 @@ PyTypeObject PySlice_Type = {
721721
0, /* tp_alloc */
722722
slice_new, /* tp_new */
723723
};
724+
725+
726+
// -- Stable ABI ------------------------------------------------------------
727+
728+
PyObject* _Py_GetEllipsis(void)
729+
{ return &_Py_EllipsisObject; }

0 commit comments

Comments
 (0)