We have a SECP256K1_GNUC_PREREQ macro (defined in terms of __GNUC__ and __GNUC_MINOR__ for checking gcc versions):
Current usage in the codebase:
❯ git grep _GNUC_
examples/examples_util.h:#elif defined(__GNUC__)
include/secp256k1.h:# if !defined(SECP256K1_GNUC_PREREQ)
include/secp256k1.h:# if defined(__GNUC__)&&defined(__GNUC_MINOR__)
include/secp256k1.h:# define SECP256K1_GNUC_PREREQ(_maj,_min) \
include/secp256k1.h: ((__GNUC__<<16)+__GNUC_MINOR__>=((_maj)<<16)+(_min))
include/secp256k1.h:# define SECP256K1_GNUC_PREREQ(_maj,_min) 0
include/secp256k1.h:# elif !defined(_WIN32) && defined (__GNUC__) && (__GNUC__ >= 4)
include/secp256k1.h:# if defined(__GNUC__) && SECP256K1_GNUC_PREREQ(3, 4)
include/secp256k1.h:# if !defined(SECP256K1_BUILD) && defined(__GNUC__) && SECP256K1_GNUC_PREREQ(3, 4)
src/checkmem.h:# elif defined(__GNUC__) && (__GNUC__ >= 15)
src/checkmem.h:# elif defined(__GNUC__) && (__GNUC__ >= 15)
src/int128_native.h:SECP256K1_GNUC_EXT typedef unsigned __int128 uint128_t;
src/int128_native.h:SECP256K1_GNUC_EXT typedef __int128 int128_t;
src/util.h:# if SECP256K1_GNUC_PREREQ(2,7)
src/util.h:#if SECP256K1_GNUC_PREREQ(3, 0)
src/util.h:# if SECP256K1_GNUC_PREREQ(3,0)
src/util.h:#if defined(__GNUC__)
src/util.h:# define SECP256K1_GNUC_EXT __extension__
src/util.h:# define SECP256K1_GNUC_EXT
src/util.h:#elif defined(__GNUC__)
src/util.h:#if (__has_builtin(__builtin_ctz) || SECP256K1_GNUC_PREREQ(3,4))
src/util.h:#if (__has_builtin(__builtin_ctzl) || SECP256K1_GNUC_PREREQ(3,4))
src/util.h:#if (__has_builtin(__builtin_ctzl) || SECP256K1_GNUC_PREREQ(3,4))
src/util.h:#if (__has_builtin(__builtin_ctzll) || SECP256K1_GNUC_PREREQ(3,4))
src/util_local_visibility.h:#if !defined(_WIN32) && defined(__GNUC__) && (__GNUC__ >= 4)
- It's currently used only for ancient GCC versions (see above). The only check against a contemporary GCC version is in
checkmem.hbut here we don't even use the macro. (#1865 would add a (4, 2) check but I consider this also ancient). If you have an ancient compiler, it's reasonable to except that you're on your own. - Contributors apparently don't remember its existence (see the
checkmem.hcase, and alsoutil_local_visibility.hand evensecp256k1.hitself). - It's misleading because
__GNUC__is defined also in Clang. Clang sets__GNUC__to 4 and__GNUC_MINOR__to 2 (mimicking GCC 4.2) by default for compatibility, regardless of the actual Clang version. Modern Clang (8+) supports-fgnuc-version=major.minor.patchto override these values, but that's of no use to us.
I suggest removing the macro and just checking defined(__GNUC__) instead (when it comes to ancient versions), or something like (__GNUC__) && (__GNUC__ >= 15), or __has_builtin when appropriate (introduced in GCC 10).