gcc has a large collection of builtins (intrinsics), as listed at https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html A useful feature would be a __has_builtin() macro, as implemented in clang: http://clang.llvm.org/docs/LanguageExtensions.html#feature-checking-macros This would allow feature detection rather than requiring checks against compiler names and versions. Support for this enhancement was expressed on the mailing list (Sep 2012) http://comments.gmane.org/gmane.comp.gcc.help/42610 but it looks like it was never submitted as a bug.
Why do you need this? Why can't you check before doing a compiling if the builtin exists? That is use autoconfig like all standard open source products do. You still need to do that for older versions of the compilers anyways.
I'd also like this feature. Not all standard open source projects use autoconf. For example, the Linux kernel doesn't. The Linux kernel *is* capable of probing for the existence of builtins, but it's a pain in the neck: it needs to write out a test .c file and try compiling it. This is slow, and it scales terribly: the configuration step wastes time proportional to the number of probed builtins probing for builtins, and the constant factor is pretty bad. It also means that the amount of work needed to use a new builtin is rather high: add a new config step and remember to use the result correctly in the code that uses the builtin. The name of the resulting macro can't really be standardized. Sure, with __has_builtin, users would still need to probe for __has_builtin itself, but that would be a single check. For builtins that are newer than __has_builtin, there would be no need to have a fallback and, for older builtins, a fallback could be added if needed. (Alternatively, the C code could simply not use the builtin on older gcc versions.)
It would also allow using builtins in installed headers more easily, e.g. for isnan, isfinite abstractions without the need of juggling version number checks. This simplifies work for stacks of software deriving from one common base library. The deriving applications could use the efficient builtins via the common base header instead of each having to add their own checks. Similarly useful would be the related __has_attribute, those especially tend to cause a huge mess of version number checks.
(In reply to Julian Taylor from comment #3) > Similarly useful would be the related __has_attribute, those especially tend > to cause a huge mess of version number checks. That's already supported: https://gcc.gnu.org/gcc-5/changes.html
This just hit us again, when a patch release removed __builtin_clzs or renamed it to __builtin_lzcnt_u16. We need to be able to detect which ones exist at compile-time otherwise we can't ship in headers that won't break when gcc updates.
> Why do you need this? 1) Because clang already supports it and people like myself would like to simplify their code i.e. have a single macro for both GCC and clang. 2) Without this macro one needs to check if a __builtin_* macro exists using the build system (Autotools, CMake) which requires more complicated code or one needs a nasty macro which checks the __GNUC__ and __GNUC_MINOR__ versions. The __has_attribute() macro is much more elegant than the other two options. > You still need to check for older versions of the > compilers (which don't support __has_attribute()) anyways. Not everybody needs to support old compiler versions. My company regularly upgrades to the latest Linux version. After such an upgrade we are allowed to use new compiler features. There are also lots of developers out there who only care if their program compiles with a fairly recent compiler (e.g. not older than 5 years). If GCC would implement __has_attribute() today than it would become very useful in just a few years.
Created attachment 42188 [details] Preliminary patch Based on the already-existing __has_attribute() support, I've developed a patch implementing this feature. Attached. After some superficial testing (./cc1 -E), it seems to be working correctly. I don't really have the resources to run regression tests, so I didn't (although I think regressions would be unlikely). I also didn't write any new tests or documentation. (I noticed __has_attribute also doesn't seem to have much of either.) I made the feature closely mimic The Other Compiler's behaviour: only function built-ins are recognised. This includes generic functions like __builtin_add_overflow and C library functions specially handled by the front-end like printf (unless -fno-builtin is used), but excludes types like __builtin_va_list and function-like constructs (implemented as keywords) like __builtin_offsetof and __builtin_types_compatible_p. This is not so much of a problem for them, since they also provide __has_feature(), __has_extension() and __is_identifier() macros. The former has been requested in PR 60512 and rejected; it may be reasonable to revisit the issue. However, if more such preprocessor, er, built-ins are desired, it may start becoming unwieldy to implement them the way I did in this patch; it involved some amount of copy-pasting.
(In reply to felix from comment #7) > Created attachment 42188 [details] > Preliminary patch > > Based on the already-existing __has_attribute() support, I've developed a > patch implementing this feature. Attached. > > After some superficial testing (./cc1 -E), it seems to be working correctly. > I don't really have the resources to run regression tests, so I didn't > (although I think regressions would be unlikely). I also didn't write any > new tests or documentation. (I noticed __has_attribute also doesn't seem to > have much of either.) > > I made the feature closely mimic The Other Compiler's behaviour: only > function built-ins are recognised. This includes generic functions like > __builtin_add_overflow and C library functions specially handled by the > front-end like printf (unless -fno-builtin is used), but excludes types like > __builtin_va_list and function-like constructs (implemented as keywords) > like __builtin_offsetof and __builtin_types_compatible_p. This is not so > much of a problem for them, since they also provide __has_feature(), > __has_extension() and __is_identifier() macros. The former has been > requested in PR 60512 and rejected; it may be reasonable to revisit the > issue. > > However, if more such preprocessor, er, built-ins are desired, it may start > becoming unwieldy to implement them the way I did in this patch; it involved > some amount of copy-pasting. Thank you for the patch! Please send it to the gcc-patches mailing list for review: https://gcc.gnu.org/ml/gcc-patches/
Can I please second this request? This would be extremely useful in the Linux kernel, *and* it would be extremely useful in any code that for whatever reason cannot depend on any particular build system.
(In reply to H. Peter Anvin from comment #9) > Can I please second this request? This would be extremely useful in the > Linux kernel, *and* it would be extremely useful in any code that for > whatever reason cannot depend on any particular build system. Well, it's already been seconded, but you can... seventh it? I dunno, I can't count.
(In reply to felix from comment #7) > I made the feature closely mimic The Other Compiler's behaviour: only > function built-ins are recognised. This includes generic functions like > __builtin_add_overflow and C library functions specially handled by the > front-end like printf (unless -fno-builtin is used), but excludes types like > __builtin_va_list and function-like constructs (implemented as keywords) > like __builtin_offsetof and __builtin_types_compatible_p. This is not so > much of a problem for them, since they also provide __has_feature(), > __has_extension() and __is_identifier() macros. I hate that behaviour. Having to use !__is_identifier(__builtin_launder) is confusing (and not just to me, but to developers of LLVM's own libc++, who I've had to explain the problem to). But consistency with Clang is probably more important than making __has_builtin behave sanely.
(In reply to Jonathan Wakely from comment #11) > (In reply to felix from comment #7) > > I made the feature closely mimic The Other Compiler's behaviour: only > > function built-ins are recognised. This includes generic functions like > > __builtin_add_overflow and C library functions specially handled by the > > front-end like printf (unless -fno-builtin is used), but excludes types like > > __builtin_va_list and function-like constructs (implemented as keywords) > > like __builtin_offsetof and __builtin_types_compatible_p. This is not so > > much of a problem for them, since they also provide __has_feature(), > > __has_extension() and __is_identifier() macros. > > I hate that behaviour. Having to use !__is_identifier(__builtin_launder) is > confusing (and not just to me, but to developers of LLVM's own libc++, who > I've had to explain the problem to). > > But consistency with Clang is probably more important than making > __has_builtin behave sanely. maybe have a separate __sane_has_builtin? That way __has_builtin could still be compatible with clang, but there'd also be a sane alternative
Let me look into this request for GCC 10.
(In reply to Martin Sebor from comment #13) > Let me look into this request for GCC 10. It's GCC 10 now.
Any progress Martin? Just to keep beating the dead horse... Forgetting other compilers for a minute, __has_builtin allows for feature detection which is much better than compiler version checks which are brittle and error prone. As new builtins get added over time, their existence can be checked in a cleaner way with __has_builtin.
No progress yet but I agree and I'm still planning to work on it for GCC 10.
(In reply to felix from comment #7) > I made the feature closely mimic The Other Compiler's behaviour: only > function built-ins are recognised. This includes generic functions like > __builtin_add_overflow and C library functions specially handled by the > front-end like printf (unless -fno-builtin is used), but excludes types like > __builtin_va_list and function-like constructs (implemented as keywords) > like __builtin_offsetof and __builtin_types_compatible_p. This is not so > much of a problem for them, since they also provide __has_feature(), > __has_extension() and __is_identifier() macros. The former has been > requested in PR 60512 and rejected; it may be reasonable to revisit the > issue. I still hate this nonsense. __builtin_offsetof is a keyword not a built-in, similar to __is_aggregate. But __builtin_launder is a built-in not a keyword, like __builtin_add_overflow. Given a built-in name, how on earth am I supposed to know how to detect it? How does a user know whether something is a "function built-in" or a "function-like construct"? #if __has_builtin(__is_aggregate) # if __is_identifier(__is_aggregate) # pragma message("__is_aggregate is a builtin and an identifier") # else # pragma message("__is_aggregate is a builtin but not an identifier") # endif #elif __is_identifier(__is_aggregate) # pragma message("__is_aggregate is not a builtin or a keyword") #else # pragma message("__is_aggregate is not a builtin but is a keyword") #endif #if __has_builtin(__builtin_launder) # if __is_identifier(__builtin_launder) # pragma message("__builtin_launder is a builtin and an identifier") # else # pragma message("__builtin_launder is a builtin but not an identifier") # endif #elif __is_identifier(__builtin_launder) # pragma message("__builtin_launder is not a builtin or a keyword") #else # pragma message("__builtin_launder is not a builtin but is a keyword") #endif #if __has_builtin(__builtin_offsetof) # if __is_identifier(__builtin_offsetof) # pragma message("__builtin_offsetof is a builtin and an identifier") # else # pragma message("__builtin_offsetof is a builtin but not an identifier") # endif #elif __is_identifier(__builtin_offsetof) # pragma message("__builtin_offsetof is not a builtin or a keyword") #else # pragma message("__builtin_offsetof is not a builtin but is a keyword") #endif __is_aggregate is not a builtin but is a keyword __builtin_launder is a builtin and an identifier __builtin_offsetof is not a builtin but is a keyword Anybody who thinks this is a clean way to detect built-ins hasn't actually had to use it.
Proper built-ins are ordinary identifiers subject to ordinary name resolution and shadowing, so the 'keyword built-in' case is impossible. If you don't know if (or don't want to depend on the fact that) a given built-in is a keyword or an intrinsic function, `__has_builtin(x) || !__is_identifier(x)` should suffice. In a way, that detail is already exposed to user code: `int __builtin_abort = 0;` compiles, but `int __builtin_choose_expr = 0;` doesn't. The documentation doesn't mention this, however; keyword built-ins are actually documented as being functions in the manual, either explicitly or implicitly (by being listed alongside true intrinsic functions with no discriminating features). So even if this feature is adopted as-is, it will necessitate some changes in the documentation. And while I can sympathise with claims that this behaviour is surprising, what are the alternatives? If keywords should count as built-ins, should __has_builtin(sizeof) expand to 1? Should __has_builtin(volatile)?
(In reply to felix from comment #18) > So even if this feature is adopted as-is, it will necessitate some changes > in the documentation. And while I can sympathise with claims that this > behaviour is surprising, what are the alternatives? If keywords should count > as built-ins, should __has_builtin(sizeof) expand to 1? Should > __has_builtin(volatile)? No just keywords that begin with __builtin_..
(In reply to Jonathan Wakely from comment #11) > I hate that behaviour. Having to use !__is_identifier(__builtin_launder) is > confusing (and not just to me, but to developers of LLVM's own libc++, who > I've had to explain the problem to). > > But consistency with Clang is probably more important than making > __has_builtin behave sanely. What if breaking that insane compatibility? How does it make things worse? `__has_builtin` is expected to be OK even with false negative results (but surely not false positive ones). Is there any real examples showing that relying on something like `!__has_builtin(__builtin_offsetof)` necessary for the needs in practice? Note that there is already no warranty by the standard with the use of `__`, and I don't ever find reasons that things like `int __builtin_abort = 0;` should work besides the leaked implementation details. Such abuse seems not documented at all. Even such use is eventually guaranteed to work, the extent should be justified by `__is_identifier`, with nothing to do with the `__builtin_` prefix.
Clang is changing __has_builtin so it recognizes all function-like built-ins, not just the ones starting with "__builtin_". See https://reviews.llvm.org/D66100 This means __has_builtin yields true for all of __is_aggregate, __builtin_launder and __builtin_offsetof.
Patch: https://gcc.gnu.org/ml/gcc-patches/2019-10/msg00062.html
Author: msebor Date: Mon Oct 28 22:46:28 2019 New Revision: 277544 URL: https://gcc.gnu.org/viewcvs?rev=277544&root=gcc&view=rev Log: PR c/66970 - Add __has_builtin() macro gcc/ChangeLog: PR c/66970 * doc/cpp.texi (__has_builtin): Document. * doc/extend.texi (__builtin_frob_return_addr): Correct spelling. gcc/c/ChangeLog: PR c/66970 * c-decl.c (names_builtin_p): Define a new function. gcc/c-family/ChangeLog: PR c/66970 * c-common.c (c_common_nodes_and_builtins): Call c_define_builtins even when only preprocessing. * c-common.h (names_builtin_p): Declare new function. * c-lex.c (init_c_lex): Set has_builtin. (c_common_has_builtin): Define a new function. * c-ppoutput.c (init_pp_output): Set has_builtin. gcc/cp/ChangeLog: PR c/66970 * cp-objcp-common.c (names_builtin_p): Define new function. gcc/testsuite/ChangeLog: PR c/66970 * c-c++-common/cpp/has-builtin-2.c: New test. * c-c++-common/cpp/has-builtin-3.c: New test. * c-c++-common/cpp/has-builtin.c: New test. Added: trunk/gcc/testsuite/c-c++-common/cpp/has-builtin-2.c trunk/gcc/testsuite/c-c++-common/cpp/has-builtin-3.c trunk/gcc/testsuite/c-c++-common/cpp/has-builtin.c Modified: trunk/gcc/ChangeLog trunk/gcc/c-family/ChangeLog trunk/gcc/c-family/c-common.c trunk/gcc/c-family/c-common.h trunk/gcc/c-family/c-lex.c trunk/gcc/c-family/c-ppoutput.c trunk/gcc/c/ChangeLog trunk/gcc/c/c-decl.c trunk/gcc/cp/ChangeLog trunk/gcc/cp/cp-objcp-common.c trunk/gcc/doc/cpp.texi trunk/gcc/doc/extend.texi trunk/gcc/testsuite/ChangeLog trunk/libcpp/include/cpplib.h trunk/libcpp/init.c trunk/libcpp/macro.c trunk/libcpp/traditional.c
Committed in r277544. Unlike in Clang, arguments to the GCC __has_builtin operator are subject to macro expansion. Also unlike in Clang (as of today), in GCC __has_builtin (__is_aggregate) && __has_builtin (__builtin_launder) && __has_builtin (__builtin_offsetof) evaluates to non-zero.