[cfe-users] __builtin_constant_p(), __builtin_expect() and __builtin_types_compatible_p() and __has_builtin()

Matthew Fernandez via cfe-users cfe-users at lists.llvm.org
Fri Aug 9 19:48:14 PDT 2019

> On Aug 9, 2019, at 14:58, Richard Smith via cfe-users <cfe-users at lists.llvm.org> wrote:
> On Fri, 9 Aug 2019 at 10:32, Chris Hall via cfe-users <cfe-users at lists.llvm.org <mailto:cfe-users at lists.llvm.org>> wrote:
> On 09/08/2019 15:00, Matthew Fernandez wrote:
> >> On Aug 9, 2019, at 05:23, Chris Hall via cfe-users wrote:
> >>
> >> I find that __builtin_constant_p() works as expected, but 
> >> __has_builtin(constant_p) denies it !
> > I believe you need __has_builtin(__builtin_constant_p).
> Ah :-(  So you do... sorry... I have no idea why I thought otherwise :-(
> >> Similarly __builtin_expect() and __builtin_types_compatible_p() !
> Except that __has_builtin(__builtin_types_compatible_p) also denies it.
>     #include <stdio.h>
>     int
>     main(int argc, char* argv[])
>     {
>       printf("__has_builtin(__builtin_types_compatible_p)=%d\n"
>                            "__builtin_types_compatible_p(int, int)=%d\n"
>                            "__builtin_types_compatible_p(int, long)=%d\n",
>               __has_builtin(__builtin_types_compatible_p),
>                             __builtin_types_compatible_p(int, int),
>                             __builtin_types_compatible_p(int, long)) ;
>     }
> outputs:
>     __has_builtin(__builtin_types_compatible_p)=0
>     __builtin_types_compatible_p(int, int)=1
>     __builtin_types_compatible_p(int, long)=0
> I hope I haven't missed something blindingly obvious this time.
> This is a historical accident.
> __has_builtin detects builtin *functions*. We also have a bunch of things that start with __builtin and look somewhat like functions, but that take types as arguments so can't actually be functions -- instead, they're keywords with custom parsing rules. __has_builtin doesn't detect those (because they're not builtin functions).
> We've fixed this for such things we added recently, such as __builtin_bit_cast and __builtin_FILE, but the older ones like __builtin_types_compatible_p and __builtin_choose_expr and __builtin_offsetof are unfortunately not detectable by __has_builtin.
> There is another way to detect these: use !__is_identifier(__builtin_types_compatible_p). That will evaluate to 1 whenever __builtin_types_compatible_p is not a valid identifier (because it's a keyword) -- that is, whenever the feature is available. However, __is_identifier was added in April 2014, and nearly all the builtins that __has_builtin can't detect are older than that. So this technique isn't really useful.

This thread taught me something too, thanks :) The __is_identifier trick seems even more tricky to use than this implies. E.g. it returns true for __builtin_constant_p because that one is implemented as a function, as you describe. Does this mean to fully detect support for __builtin_foo I need something like `__has_builtin(foo) || __has_builtin(__builtin_foo) || !__is_identifier(__builtin_foo)`?

While we’re on this topic, are the semantics of __is_identifier just “is not a keyword”? I ask because even when it returns true for a __-prefixed symbol, it’s not an indication you can use it in user code because it’s still reserved for use by the implementation. In fact __is_identifier even returns true for itself, which I guess is technically correct.

> In practice, every version of Clang from the past 10 years supports __builtin_types_compatible_p (in C mode). So you can just assume it exists.

This is what I do too, as it’s widely supported back to every reasonable version of GCC as well.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-users/attachments/20190809/c0d162d8/attachment.html>

More information about the cfe-users mailing list