On 10/1/19 11:38 AM, Jakub Jelinek wrote:
On Tue, Oct 01, 2019 at 11:16:10AM -0600, Martin Sebor wrote:
Attached is an implementation of the __has_builtin special
preprocessor operator/macro analogous to __has_attribute and
(hopefully) compatible with the synonymous Clang feature (I
couldn't actually find tests for it in the Clang test suite
but if someone points me at them I'll verify it).

For the __builtin_*/__sync_*/__atomic_* etc. builtins whether something
is a builtin or not is quite clear, basically whether if using the right
operands for it will compile and do something.
For the library functions, what does it mean that something is a builtin
though?  In some cases we have them in the builtin tables only
to have some predefined attributes for them, in other cases because the
compiler is aware of some of their special properties, in other cases that
the compiler will sometimes optimize them into something else or inline them
and at other times keep them as a library calls, in some cases only for the
compiler to be able to emit calls to those routines in generated code,
in other cases to always optimize them/inline them and never emit the
library function (which perhaps doesn't exist).
I believe that for some builtins like stpcpy we treat them as builtins only
if we see them prototyped first.
And then for C++ with namespaces and symbol lookup rules, whether something
is or isn't a builtin depends not just on the identifier, but namespace too
and maybe argument types too.

So, what do we want __has_builtin to mean for those?

Say, do we want __has_builtin (_exit) just because we have it in the tables
to 1) add noreturn/nothrow/leaf attributes to it 2) consider it in branch
prediction heuristics, but otherwise don't do anything special with it?

As I understand it from the Clang manual and my limited testing, __has_builtin is supposed to evaluate to true if the argument is
recognized as the name of a built-in function or function-like
operator.

The number of arguments to the built-in or their types are not
considered in this context (or even available).  Neither are
other declarations of the same symbol.

The intent is simply to determine whether the name can be used
but not how or to what effect.

This is similar to other such queries like __has_attribute which
also doesn't consider the number of attribute operands, or what
the attribute can apply to, or what its effect might be.  Likewise
for __has_include which evaluates to true when the referenced
header can be found by an #include directive without implying
that #including it will not trigger errors for what's in
the header.

Martin

PS As an example, this complete test case passes with both
compilers unless abs is disabled with -fno-builtin.

  #if !__has_builtin (abs)
  # error "__has_builtin (abs) --> false"
  #endif

Ditto if abs is declared as a different symbol first, effectively
preventing the built-in abs from being used.

Reply via email to