diff --git a/Doc/c-api/intro.rst b/Doc/c-api/intro.rst index 701d2a31b8c905..5f1c87c5aa72a6 100644 --- a/Doc/c-api/intro.rst +++ b/Doc/c-api/intro.rst @@ -227,6 +227,10 @@ The following macros are for common tasks not specific to Python. Use this for unused arguments in a function definition to silence compiler warnings. Example: ``int func(int a, int Py_UNUSED(b)) { return a; }``. + The macro mangles *name* so that it cannot be used, and when possible, + applies the C23/C++17 attribute ``[[maybe_unused]]`` or a compiler-specific + equivalent. + .. versionadded:: 3.4 .. c:macro:: Py_GCC_ATTRIBUTE(name) diff --git a/Include/pymacro.h b/Include/pymacro.h index 41dfd9155b9b24..aa2ce507a83d9a 100644 --- a/Include/pymacro.h +++ b/Include/pymacro.h @@ -254,7 +254,9 @@ * * int func(int a, int Py_UNUSED(b)) { return a; } */ -#if defined(__GNUC__) || defined(__clang__) +#if _Py__has_c_cpp_attribute(maybe_unused) +# define Py_UNUSED(name) _unused_ ## name _Py_C_ATTRIBUTE(maybe_unused) +#elif defined(__GNUC__) || defined(__clang__) # define Py_UNUSED(name) _unused_ ## name __attribute__((unused)) #elif defined(_MSC_VER) // Disable warning C4100: unreferenced formal parameter, diff --git a/Include/pyport.h b/Include/pyport.h index 1af2b61eeacd28..503959bfcd7388 100644 --- a/Include/pyport.h +++ b/Include/pyport.h @@ -27,6 +27,52 @@ # define _Py__has_attribute(x) 0 #endif +// Same check for C23 [[attribute]]. +#ifdef __has_c_attribute +# define _Py__has_c_attribute(X) __has_c_attribute(X) +#else +# define _Py__has_c_attribute(X) 0 +#endif + +// Same check for C++17 [[attribute]]. +#if defined(__cpp_attributes) && defined(__has_cpp_attribute) +# define _Py__has_cpp_attribute(X) __has_cpp_attribute(X) +#else +# define _Py__has_cpp_attribute(X) 0 +#endif + +// Combined check for C & C++ [[attribute]]. Only use if attribute works +// the same way in both languages. +#ifdef __cplusplus +# define _Py__has_c_cpp_attribute(X) _Py__has_cpp_attribute(X) +#else +# define _Py__has_c_cpp_attribute(X) _Py__has_c_attribute(X) +#endif + +// _Py_C_ATTRIBUTE(attribute): wrapper for [[attribute]] +#if defined(__GNUC__) && !defined(__clang__) && defined(__STDC_VERSION__) && __STDC_VERSION__ < 202311L +// In GCC pedantic mode before C23, `__has_c_attribute` is defined but using +// C attributes emits warnings. Suppress them. +# define _Py_C_ATTRIBUTE(ATTR) [[__extension__ ATTR]] +#elif defined(__clang__) && defined(__STDC_VERSION__) && __STDC_VERSION__ < 202311L +// Similar for clang and C23. It's not clear how to suppress this, +// so pretend the feature is missing. +# undef _Py__has_cpp_attribute +# undef _Py__has_c_cpp_attribute +# define _Py__has_cpp_attribute(X) 0 +# define _Py__has_c_cpp_attribute(X) 0 +# define _Py_C_ATTRIBUTE(ATTR) +#elif defined(__clang__) && defined(__cplusplus) && __cplusplus < 201703L +// Same for clang and C++17. +# undef _Py__has_c_attribute +# undef _Py__has_c_cpp_attribute +# define _Py__has_c_attribute(X) 0 +# define _Py__has_c_cpp_attribute(X) 0 +# define _Py_C_ATTRIBUTE(ATTR) +#else +# define _Py_C_ATTRIBUTE(ATTR) [[ATTR]] +#endif + // Macro to use C++ static_cast<> in the Python C API. #ifdef __cplusplus # define _Py_STATIC_CAST(type, expr) static_cast(expr)