> On Aug 9, 2019, at 14:58, Richard Smith via cfe-users 
> <cfe-users@lists.llvm.org> wrote:
> 
> On Fri, 9 Aug 2019 at 10:32, Chris Hall via cfe-users 
> <cfe-users@lists.llvm.org <mailto:cfe-users@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.
_______________________________________________
cfe-users mailing list
cfe-users@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-users

Reply via email to