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

Richard Smith via cfe-users cfe-users at lists.llvm.org
Mon Aug 12 11:35:03 PDT 2019

On Fri, 9 Aug 2019 at 19:48, Matthew Fernandez <matthew.fernandez at gmail.com>

> 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> 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)`?

Approximately all the function-like things that could be functions (that
is, where a use can be parsed as a function call, and in particular where
none of the arguments are types) are functions, and can be detected with
__has_builtin. Things that must have custom parsing logic are modeled as
keywords and can be detected by __is_identifier. You should never need both.

(In https://reviews.llvm.org/D66100 I'm proposing that we extend
__has_builtin to also be able to identify the builtins that we model as
keywords, but sadly that does nothing for versions of Clang we've already
released, so you still need to use the old techniques there.)

> 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.

It's "is identifier", which (for identifier-shaped tokens) is almost but
not quite "is not a keyword", due to things like "and" which in C++ is
neither an identifier nor a keyword.

> 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/20190812/45572900/attachment.html>

More information about the cfe-users mailing list