gh-89653: PEP 670: Convert PyUnicode_KIND() macro to function
diff --git a/Include/cpython/unicodeobject.h b/Include/cpython/unicodeobject.h
index 8c53962437b6e0..030614e263344d 100644
--- a/Include/cpython/unicodeobject.h
+++ b/Include/cpython/unicodeobject.h
@@ -242,9 +242,23 @@ enum PyUnicode_Kind {
     PyUnicode_4BYTE_KIND = 4
 };
 
-/* Return one of the PyUnicode_*_KIND values defined above. */
+// PyUnicode_KIND(): Return one of the PyUnicode_*_KIND values defined above.
+#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 < 0x030c0000
+// gh-89653: Converting this macro to a static inline function would introduce
+// new compiler warnings on "kind < PyUnicode_KIND(str)" (compare signed and
+// unsigned numbers) where kind type is an int or on
+// "unsigned int kind = PyUnicode_KIND(str)" (cast signed to unsigned).
+// Only declare the function as static inline function in the limited C API
+// version 3.12 which is stricter.
 #define PyUnicode_KIND(op) \
     (_PyASCIIObject_CAST(op)->state.kind)
+#else
+// Limited C API 3.12 and newer
+static inline int PyUnicode_KIND(PyObject *op) {
+    assert(PyUnicode_IS_READY(op));
+    return _PyASCIIObject_CAST(op)->state.kind;
+}
+#endif
 
 /* Return a void pointer to the raw unicode buffer. */
 static inline void* _PyUnicode_COMPACT_DATA(PyObject *op) {
diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c
index 65885965ff046d..5cbddac6232487 100644
--- a/Modules/_decimal/_decimal.c
+++ b/Modules/_decimal/_decimal.c
@@ -1933,7 +1933,7 @@ is_space(enum PyUnicode_Kind kind, const void *data, Py_ssize_t pos)
    Return NULL if malloc fails and an empty string if invalid characters
    are found. */
 static char *
-numeric_as_ascii(const PyObject *u, int strip_ws, int ignore_underscores)
+numeric_as_ascii(PyObject *u, int strip_ws, int ignore_underscores)
 {
     enum PyUnicode_Kind kind;
     const void *data;
@@ -2047,7 +2047,7 @@ PyDecType_FromCStringExact(PyTypeObject *type, const char *s,
 
 /* Return a new PyDecObject or a subtype from a PyUnicodeObject. */
 static PyObject *
-PyDecType_FromUnicode(PyTypeObject *type, const PyObject *u,
+PyDecType_FromUnicode(PyTypeObject *type, PyObject *u,
                       PyObject *context)
 {
     PyObject *dec;
@@ -2067,7 +2067,7 @@ PyDecType_FromUnicode(PyTypeObject *type, const PyObject *u,
  * conversion. If the conversion is not exact, fail with InvalidOperation.
  * Allow leading and trailing whitespace in the input operand. */
 static PyObject *
-PyDecType_FromUnicodeExactWS(PyTypeObject *type, const PyObject *u,
+PyDecType_FromUnicodeExactWS(PyTypeObject *type, PyObject *u,
                              PyObject *context)
 {
     PyObject *dec;
@@ -2150,7 +2150,7 @@ PyDecType_FromSsizeExact(PyTypeObject *type, mpd_ssize_t v, PyObject *context)
 /* Convert from a PyLongObject. The context is not modified; flags set
    during conversion are accumulated in the status parameter. */
 static PyObject *
-dec_from_long(PyTypeObject *type, const PyObject *v,
+dec_from_long(PyTypeObject *type, PyObject *v,
               const mpd_context_t *ctx, uint32_t *status)
 {
     PyObject *dec;
@@ -2201,7 +2201,7 @@ dec_from_long(PyTypeObject *type, const PyObject *v,
 /* Return a new PyDecObject from a PyLongObject. Use the context for
    conversion. */
 static PyObject *
-PyDecType_FromLong(PyTypeObject *type, const PyObject *v, PyObject *context)
+PyDecType_FromLong(PyTypeObject *type, PyObject *v, PyObject *context)
 {
     PyObject *dec;
     uint32_t status = 0;
@@ -2227,7 +2227,7 @@ PyDecType_FromLong(PyTypeObject *type, const PyObject *v, PyObject *context)
 /* Return a new PyDecObject from a PyLongObject. Use a maximum context
    for conversion. If the conversion is not exact, set InvalidOperation. */
 static PyObject *
-PyDecType_FromLongExact(PyTypeObject *type, const PyObject *v,
+PyDecType_FromLongExact(PyTypeObject *type, PyObject *v,
                         PyObject *context)
 {
     PyObject *dec;
diff --git a/Objects/stringlib/eq.h b/Objects/stringlib/eq.h
index 2f2438845a629c..2eac4baf5ca9ce 100644
--- a/Objects/stringlib/eq.h
+++ b/Objects/stringlib/eq.h
@@ -6,9 +6,6 @@
 Py_LOCAL_INLINE(int)
 unicode_eq(PyObject *a, PyObject *b)
 {
-    assert(PyUnicode_Check(a));
-    assert(PyUnicode_Check(b));
-
     if (PyUnicode_GET_LENGTH(a) != PyUnicode_GET_LENGTH(b))
         return 0;
     if (PyUnicode_GET_LENGTH(a) == 0)

In the limited C API version 3.12, PyUnicode_KIND() is now
implemented as a static inline function. Keep the macro for the
regular C API and for the limited C API version 3.11 and older to
prevent introducing new compiler warnings.

Update _decimal.c and stringlib/eq.h for PyUnicode_KIND().

<!--
Thanks for your contribution!
Please read this comment in its entirety. It's quite important.

# Pull Request title

It should be in the following format:

```
gh-NNNNN: Summary of the changes made
```

Where: gh-NNNNN refers to the GitHub issue number.

Most PRs will require an issue number. Trivial changes, like fixing a typo, do not need an issue.

# Backport Pull Request title

If this is a backport PR (PR made against branches other than `main`),
please ensure that the PR title is in the following format:

```
[X.Y] <title from the original PR> (GH-NNNN)
```

Where: [X.Y] is the branch name, e.g. [3.6].

GH-NNNN refers to the PR number from `main`.

-->
