> 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