[PATCH] New syntax and functionality for __has_attribute

The __has_attribute feature macro is fantastic in many respects, but
is lacking the ability to determine whether a specific attribute
syntax is available or not. Instead, it currently checks whether the
attribute is known within the compilation target, and nothing more.
This can cause problems because not all attributes are applied in the
same way.

Consider dllexport as a contrived example:

#if __has_attribute(dllexport)
  void foo(void) __attribute__((dllexport));
#endif

This code looks fine, but is actually broken because clang only
supports __declspec(dllexport) and not __attribute__((dllexport)), and
__declspec must precede the declaration.

The attached patch implements new syntax for __has_attribute while
retaining backwards compatibility. It allows you to specify exactly
which attribute syntax you desire. If no specific syntax is specified,
it behaves as it always has.

The supported forms are:

__has_attribute(__attribute__((ident))) // GNU-style
__has_attribute(__declspec(ident)) // MS-style
__has_attribute([[ident]]) // C++11-style
__has_attribute([[scope::ident]]) // C++11-style
__has_attribute(ident) // Keywords, or "don't care"

Note that attribute arguments are not supported by design -- they
really don't make any sense in the context of a feature macro.

~Aaron

HasAttribute.patch (18.3 KB)

I’m not sure this is necessary - do any compilers (including different versions of clang itself, which I believe is the main use of has_attribute) support the same attribute but in differing syntaxes? Otherwise it just seems an invariant of the attribute and not something that would need compile time tests for because it won’t vary by compilation

I'm not sure this is necessary - do any compilers (including different
versions of clang itself, which I believe is the main use of has_attribute)
support the same attribute but in differing syntaxes?

Yes, clang has numerous attributes instances of this. I believe GCC
does as well. For instance, it's quite common to have a GNU spelling
and a C++11 syntax for the same attribute. There are also cases where
attributes with the same spelling but different syntax provide
differing semantics, such as the aligned attribute (which has five
different syntaxes).

Otherwise it just
seems an invariant of the attribute and not something that would need
compile time tests for because it won't vary by compilation

I strongly disagree. Consider the dllexport example I had given.
Supporting that is currently guess-work with __has_attribute because
we only respond back that the attribute is known, but not a particular
syntax. Yet the syntax is specifically required in order to use it
properly.

FWIW, this is also PR15853.

~Aaron

The __has_attribute feature macro is fantastic in many respects, but
is lacking the ability to determine whether a specific attribute
syntax is available or not. Instead, it currently checks whether the
attribute is known within the compilation target, and nothing more.
This can cause problems because not all attributes are applied in the
same way.

Consider dllexport as a contrived example:

#if __has_attribute(dllexport)
   void foo(void) __attribute__((dllexport));
#endif

This code looks fine, but is actually broken because clang only
supports __declspec(dllexport) and not __attribute__((dllexport)), and
__declspec must precede the declaration.

The attached patch implements new syntax for __has_attribute while
retaining backwards compatibility. It allows you to specify exactly
which attribute syntax you desire. If no specific syntax is specified,
it behaves as it always has.

The supported forms are:

__has_attribute(__attribute__((ident))) // GNU-style
__has_attribute(__declspec(ident)) // MS-style
__has_attribute([[ident]]) // C++11-style
__has_attribute([[scope::ident]]) // C++11-style
__has_attribute(ident) // Keywords, or "don't care"

Note that attribute arguments are not supported by design -- they
really don't make any sense in the context of a feature macro.

Hi Aaron,

This is a step forward with some long-standing problems so certainly would be a step forward. The syntax is unconventional but not unreasonable.

Have you confirmed that the new __has_attribute() syntax can still be defined to an empty expansion? That pattern is important to provide source compatibility with gcc / MSVC. The latter in particular has fairly different expansion rules to watch out for -- I've got a feeling it'll be OK as long as no commas appear in the argument list (which was a problem with the other proposed "cxx, ..." syntax) but it's worth double checking.

Alp.

I’m not sure this is necessary - do any compilers (including different
versions of clang itself, which I believe is the main use of has_attribute)
support the same attribute but in differing syntaxes?

Yes, clang has numerous attributes instances of this. I believe GCC
does as well. For instance, it’s quite common to have a GNU spelling
and a C++11 syntax for the same attribute. There are also cases where
attributes with the same spelling but different syntax provide
differing semantics, such as the aligned attribute (which has five
different syntaxes).

Sorry, I’m not trying to be obtuse, but I’m not sure if/how that answers my question.

What I’m asking is, is there ever a case where a compile-time check is required to decide which syntax to use? (where two compilers (including two different versions of the same compiler) have support for the same attribute but in disparate syntaxes?)

The existence of an attribute with more than one, or less than all syntaxes is not an issue - if in every compiler that implements the attribute it is implemented in the same set of syntaxes, then there’s no need to query which syntax is valid, is there? It would be a universal constant.

Otherwise it just
seems an invariant of the attribute and not something that would need
compile time tests for because it won’t vary by compilation

I strongly disagree. Consider the dllexport example I had given.
Supporting that is currently guess-work with __has_attribute because
we only respond back that the attribute is known, but not a particular
syntax.

Wouldn’t it be documented somewhere? Why would it need to be queried dynamically (at compile-time)? That would only be necessary if the attribute was supported with different syntaxes in different compilers. Is that the case?

Yet the syntax is specifically required in order to use it
properly.

FWIW, this is also PR15853.

OK, the unparsability problem could be addressed separately, though. I guess that’s why GCC’s attribute syntax has the double parens.

But I see from the bug Richard suggested this - I’m just trying to understand it.

There's currently a test in the test suite which I think covers this case:

// CHECK: has_has_attribute
#ifdef __has_attribute
int has_has_attribute();
#endif

Is that what you are referring to? If so, then yes, this patch does
still meet that need.

Thanks!

~Aaron

The __has_attribute feature macro is fantastic in many respects, but
is lacking the ability to determine whether a specific attribute
syntax is available or not. Instead, it currently checks whether the
attribute is known within the compilation target, and nothing more.
This can cause problems because not all attributes are applied in the
same way.

Consider dllexport as a contrived example:

#if __has_attribute(dllexport)
    void foo(void) __attribute__((dllexport));
#endif

This code looks fine, but is actually broken because clang only
supports __declspec(dllexport) and not __attribute__((dllexport)), and
__declspec must precede the declaration.

The attached patch implements new syntax for __has_attribute while
retaining backwards compatibility. It allows you to specify exactly
which attribute syntax you desire. If no specific syntax is specified,
it behaves as it always has.

The supported forms are:

__has_attribute(__attribute__((ident))) // GNU-style
__has_attribute(__declspec(ident)) // MS-style
__has_attribute([[ident]]) // C++11-style
__has_attribute([[scope::ident]]) // C++11-style
__has_attribute(ident) // Keywords, or "don't care"

Note that attribute arguments are not supported by design -- they
really don't make any sense in the context of a feature macro.

Hi Aaron,

This is a step forward with some long-standing problems so certainly would
be a step forward. The syntax is unconventional but not unreasonable.

Have you confirmed that the new __has_attribute() syntax can still be
defined to an empty expansion? That pattern is important to provide source
compatibility with gcc / MSVC. The latter in particular has fairly different
expansion rules to watch out for -- I've got a feeling it'll be OK as long
as no commas appear in the argument list (which was a problem with the other
proposed "cxx, ..." syntax) but it's worth double checking.

There's currently a test in the test suite which I think covers this case:

// CHECK: has_has_attribute
#ifdef __has_attribute
int has_has_attribute();
#endif

Is that what you are referring to? If so, then yes, this patch does
still meet that need.

Sorry, I wasn't particularly clear :slight_smile:

The ifdef/undef ability for __has_attribute in clang itself is clearly fine..

I was referring rather to the compatibility, in practice, of the following pattern (as seen in LLVM's Compiler.h):

#ifndef __has_attribute
# define __has_attribute(x) 0
#endif

This would potentially have been a problem with syntax (2) proposed by Richard Smith in PR15853 given that commas are macro argument delimiters, and compounded by the fact that Microsoft has a different take on variadic macros. That would have made it difficult or impossible to provide an empty macro definition fallback for non-clang compilers.

What I'm wondering is whether your proposed __has_attribute syntax has any similar expansion problems, taking into account the kinds of arguments it accepts.

I'm hopeful that there won't be a problem because you've already intentionally excluded attribute arguments from the syntax, therefore commas can't appear -- but it's still worth checking this to see if the various attribute token sequences work in practice with third-party preprocessors.

Alp.

> I'm not sure this is necessary - do any compilers (including different
> versions of clang itself, which I believe is the main use of
> has_attribute)
> support the same attribute but in differing syntaxes?

Yes, clang has numerous attributes instances of this. I believe GCC
does as well. For instance, it's quite common to have a GNU spelling
and a C++11 syntax for the same attribute. There are also cases where
attributes with the same spelling but different syntax provide
differing semantics, such as the aligned attribute (which has five
different syntaxes).

Sorry, I'm not trying to be obtuse, but I'm not sure if/how that answers my
question.

It's likely I didn't understand the question, so keep poking me until
I get it right. :slight_smile:

What I'm asking is, is there ever a case where a compile-time check is
required to decide which syntax to use? (where two compilers (including two
different versions of the same compiler) have support for the same attribute
but in disparate syntaxes?)

The existence of an attribute with more than one, or less than all syntaxes
is not an issue - if in every compiler that implements the attribute it is
implemented in the same set of syntaxes, then there's no need to query which
syntax is valid, is there? It would be a universal constant.

I may still be totally misunderstanding your concern, so I apologize
if I'm being dense. But yes, there are cases where this comes up.
Going back to my dllexport example since I think it's the most
easily-recognizable. Here's a probably example of using this code in a
cross-compiler code base:

#if __has_attribute(dllexport)
  #define DLLEXPORT __attribute__((dllexport))
#else
  #define DLLEXPORT
#endif

void func(void) DLLEXPORT;

If you were to use this code today in clang, it would fail to compile.
__has_attribute(dllexport) will be replaced with 1, and so the
resulting code would become: void func(void)
__attribute__((dllexport)); However, we do not support dllexport with
that syntax (we only support __declspec(dllexport)). So the code would
look reasonable, but fail to compile.

We could solve this by making __has_attribute *only* correspond to
GNU-style attributes, but that's not how it works currently, and such
a change could break existing code that currently works.

Not every compiler implements the same set of attributes, which is why
__has_attribute exists in the first place. Furthermore, not every
compiler implements a given attribute with the same set of syntaxes
(such as dllexport, which is implemented in gcc as both a GNU-style
and an MS-style attribute, but it only an MS-style attribute in
clang). Even in situations where the compiler *does* implement all of
the syntaxes consistently, it can be beneficial to know which syntax
you are referring to within the context of __has_attribute because
attribute placement is different between varying attribute syntaxes.

Does that clear things up, or am I still not understanding your concerns?

> Otherwise it just
> seems an invariant of the attribute and not something that would need
> compile time tests for because it won't vary by compilation

I strongly disagree. Consider the dllexport example I had given.
Supporting that is currently guess-work with __has_attribute because
we only respond back that the attribute is known, but not a particular
syntax.

Wouldn't it be documented somewhere? Why would it need to be queried
dynamically (at compile-time)? That would only be necessary if the attribute
was supported with different syntaxes in different compilers. Is that the
case?

Yes, it is the case where the attribute is supported in different
syntaxes in different compilers. That's why I keep picking on
dllexport as an example. MSVC and clang support it as
__declspec(dllexport) only, GCC supports it as __declspec(dllexport)
or __attribute__((dllexport)).

~Aaron

No, I think I'm just a bit more dense today than usual. I blame it on
the weather. :wink:

I tried:

#define __has_attribute(x) 0

#if __has_attribute([[clang::fallthrough]])
sdfsdfsfsd
#endif

#if __has_attribute(__attribute__((weakref)))
dsfdfsdf
#endif

#if __has_attribute(__declspec(dllexport))
sdfsdf
#endif

This compiles without errors or warnings in MSVC 2013, 2012 and 2010.
Same for gcc 4.8.1.

Great question (once I understood it), btw!

~Aaron

How will a more advanced __has_attribute help here since GCC and MSVC
all reject this trailing attribute (and Clang rightfully warns about this)?

-Nico

It was meant to be expository in that there are situations where the
syntax support differs. The same statement would be true were the
attribute positioned properly. clang supports __declspec(dllexport),
but does not support __attribute__((dllexport)).

However, I did notice something interesting -- we don't support that
syntax in a declarative sense (Attr.td does not list a spelling for
it), but dllexport and dllimport are silently accepted by clang and
the attributes are attached to the decl. That doesn't really change
the desire for this feature (it's not meant as a way to handle
dllexport -- more general than that), but it is something I am
exploring a bit further as that should not be the case.

~Aaron

That's what I wondered when reading your examples, since I have been
using __attribute__((dllexport)) just fine for quite a while. And GCC
also accepts both variants.

-Nico

This is off-topic slightly, but...

I can see how this would be incredibly confusing. :smiley: This appears to
be a behavior of the way we handle attributes. The parser creates a
parsed attribute by saying "here's the name, here's the syntax used,
here are the args I got, etc" and then eventually sema gets around to
turning that into a semantic attribute. However,
AttributeList::getAttrKind only pays attention to the name and not the
syntax used. Since dllexport is known to be an
AttributeList::AT_DllExport, everything just flows through as normal.
That should probably be rectified at some point, though we'll have to
carefully watch to see how the effect shakes out as some attributes
which work (like dllexport) would then break. Fixing them should
hopefully be trivial, though.

~Aaron

That’s good news – thanks for confirming. The feature detection macro itself will still need to have a different name (or some other mechanism) so it can be used compatibly with existing clang deployments, because _has_attribute() currently emits a parse error instead of gracefully returning 0 when passed the new argument syntax: For forward compatibility your new version should warn, rather than emitting an error, upon encountering invalid attribute syntaxes that may be valid in future standards or other language dialects (e.g. single-braced C++/CLI attributes should return 0, indicating “unsupported” rather than triggering a parse error). What’s clear is that _has_attribute() isn’t fit for purpose in its current form in ToT – David Blaikie made some general arguments against the overall value of attribute feature detection. Assuming however that it’s a desirable feature to keep around in any form I think your proposal is the strongest contender for PR15853. Alp.

It’s likely I didn’t understand the question, so keep poking me until
I get it right. :slight_smile:

Let’s see how we go.

What I’m asking is, is there ever a case where a compile-time check is
required to decide which syntax to use? (where two compilers (including two
different versions of the same compiler) have support for the same attribute
but in disparate syntaxes?)

The existence of an attribute with more than one, or less than all syntaxes
is not an issue - if in every compiler that implements the attribute it is
implemented in the same set of syntaxes, then there’s no need to query which
syntax is valid, is there? It would be a universal constant.

I may still be totally misunderstanding your concern, so I apologize
if I’m being dense. But yes, there are cases where this comes up.
Going back to my dllexport example since I think it’s the most
easily-recognizable. Here’s a probably example of using this code in a
cross-compiler code base:

#if __has_attribute(dllexport)
#define DLLEXPORT attribute((dllexport))
#else
#define DLLEXPORT
#endif

void func(void) DLLEXPORT;

If you were to use this code today in clang, it would fail to compile.
__has_attribute(dllexport) will be replaced with 1, and so the
resulting code would become: void func(void)
attribute((dllexport)); However, we do not support dllexport with
that syntax (we only support __declspec(dllexport)). So the code would
look reasonable, but fail to compile.

Sure - my argument here is this is /potentially/ just a lack of documentation. It’s perhaps no more relevant than having a macro that tells you whether the return type is written “ func();” or “func() void” - it’s an invariant of the language (or an invariant of the language extension, in the attribute case), not something that needs compile-time detection.

We could solve this by making __has_attribute only correspond to
GNU-style attributes, but that’s not how it works currently, and such
a change could break existing code that currently works.

I don’t think that’s necessary. If each attribute has a documented list of syntaxes/valid places, that should be sufficient.

Not every compiler implements the same set of attributes, which is why
__has_attribute exists in the first place.

Sure - I get that, I’m not questioning the motivation for __has_attribute as it stands today. I’m questioning the value of the ability to query for particular attribute syntax/spelling support that’s being added here.

Furthermore, not every
compiler implements a given attribute with the same set of syntaxes
(such as dllexport, which is implemented in gcc as both a GNU-style
and an MS-style attribute, but it only an MS-style attribute in
clang).

OK - this is what I’m interested in, but on further consideration I think there’s an even stronger requirement:

For the has_feature per-syntax checking to be useful, we would have to be in a world in which two compilers (including different versions of the same compiler) support the same attribute in non-overlapping syntaxes.

Anyone trying to write portable code isn’t going to write:

#if __has_attribute(attribute((dllexport)))
#define DLLEXPORT attribute((dllexport))
#elif __has_attribute(declspec(dllexport))
#define DLLEXPORT declspec(dllexport)
#else
#define DLLEXPORT
#endif

They’re just going to use the common subset that all compiler support (because generally these attributes have been implemented for compatibility with other compilers, yes?), thus just preferring the MS syntax in all cases.

One difference would be that having specific syntax feature detection would allow safe fallback - if someone had written the dllexport with GCC syntax using this new feature then on Clang it would’ve silently not exported (do people actually ever want that? For some attributes there’s a logical fallback to just not use the attribute, dllexport/import doesn’t seem to be one of those - but that’s an aside) - whereas without the syntax-specific check you’d get an error and need to update the attribute syntax used in the DLLEXPORT macro to the one that’s common between GCC and Clang (& whatever else).

Even in situations where the compiler does implement all of
the syntaxes consistently, it can be beneficial to know which syntax
you are referring to within the context of __has_attribute because
attribute placement is different between varying attribute syntaxes.

Again, this knowledge would be gained through explicit compiler documentation (as any other language feature or language extension) - not necessarily meriting a compile-time query system.

Does that clear things up, or am I still not understanding your concerns?

We’re closer on the concerns, but I’m still not quite understanding the justification.

Otherwise it just
seems an invariant of the attribute and not something that would need
compile time tests for because it won’t vary by compilation

I strongly disagree. Consider the dllexport example I had given.
Supporting that is currently guess-work with __has_attribute because
we only respond back that the attribute is known, but not a particular
syntax.

Wouldn’t it be documented somewhere? Why would it need to be queried
dynamically (at compile-time)? That would only be necessary if the attribute
was supported with different syntaxes in different compilers. Is that the
case?

Yes, it is the case where the attribute is supported in different
syntaxes in different compilers. That’s why I keep picking on
dllexport as an example. MSVC and clang support it as
__declspec(dllexport) only, GCC supports it as __declspec(dllexport)
or attribute((dllexport)).

Yep, it’s a useful example (except I’m not sure it has a logical fallback, so I’m not sure how much people would actually conditionalize/feature-detect its use - and I assume GCC’s support for multiple syntaxes is more or less by accident (I assume they support all attributes in all syntaxes just as a consequence of their implementation) & really the only one people /really/ would use would be the declspec version).

  • David

That's good news -- thanks for confirming.

The feature detection macro itself will still need to have a different name
(or some other mechanism) so it can be used compatibly with existing clang
deployments, because _has_attribute() currently emits a parse error instead
of gracefully returning 0 when passed the new argument syntax:

tmp/attr2.cpp:1:5: error: builtin feature check macro requires a
parenthesized identifier
#if __has_attribute(__attribute__((weakref)))
    ^

Good catch. Unfortunately, __has_attribute is really the best
identifier for the macro, so I am loathe to let it go.

Due to the current design of __has_attribute, we can't get away with "
magic" by expanding the non-function-like form into a value that could
be tested. So we would really have to pick a new name if we are
worried about this.

Suggestions on the name are welcome. Regardless of the name picked, if
it's different from __has_attribute, we should deprecate the existing
usage since the proposed implementation is backwards compatible and
the existing __has_attribute is not forwards-compatible.

For forward compatibility your new version should warn, rather than emitting
an error, upon encountering invalid attribute syntaxes that may be valid in
future standards or other language dialects (e.g. single-braced C++/CLI
attributes should return 0, indicating "unsupported" rather than triggering
a parse error).

I agree, and will implement for the next round.

~Aaron

It's likely I didn't understand the question, so keep poking me until
I get it right. :slight_smile:

Let's see how we go.

> What I'm asking is, is there ever a case where a compile-time check is
> required to decide which syntax to use? (where two compilers (including
> two
> different versions of the same compiler) have support for the same
> attribute
> but in disparate syntaxes?)
>
> The existence of an attribute with more than one, or less than all
> syntaxes
> is not an issue - if in every compiler that implements the attribute it
> is
> implemented in the same set of syntaxes, then there's no need to query
> which
> syntax is valid, is there? It would be a universal constant.

I may still be totally misunderstanding your concern, so I apologize
if I'm being dense. But yes, there are cases where this comes up.
Going back to my dllexport example since I think it's the most
easily-recognizable. Here's a probably example of using this code in a
cross-compiler code base:

#if __has_attribute(dllexport)
  #define DLLEXPORT __attribute__((dllexport))
#else
  #define DLLEXPORT
#endif

void func(void) DLLEXPORT;

If you were to use this code today in clang, it would fail to compile.
__has_attribute(dllexport) will be replaced with 1, and so the
resulting code would become: void func(void)
__attribute__((dllexport)); However, we do not support dllexport with
that syntax (we only support __declspec(dllexport)). So the code would
look reasonable, but fail to compile.

Sure - my argument here is this is /potentially/ just a lack of
documentation. It's perhaps no more relevant than having a macro that tells
you whether the return type is written "<here> func();" or "func() void" -
it's an invariant of the language (or an invariant of the language
extension, in the attribute case), not something that needs compile-time
detection.

We could solve this by making __has_attribute *only* correspond to
GNU-style attributes, but that's not how it works currently, and such
a change could break existing code that currently works.

I don't think that's necessary. If each attribute has a documented list of
syntaxes/valid places, that should be sufficient.

Then why have __has_attribute in the first place? After all, each
vendor has a documented list of attributes they support, and there are
ways to determine which vendor-specific version is compiling the code.

This is a feature-test macro. It makes sense to test which feature is
supported. __has_attribute(ident) does not provide sufficient
resolution to determine whether the feature is supported. The proposed
feature has the granularity required, and can be written in a
future-proof manner (unlike the existing implementation).

Not every compiler implements the same set of attributes, which is why
__has_attribute exists in the first place.

Sure - I get that, I'm not questioning the motivation for __has_attribute as
it stands today. I'm questioning the value of the ability to query for
particular attribute syntax/spelling support that's being added here.

The rationale is the same either way. Outside of the
standards-required attributes, each vendor can choose to implement any
syntax and spelling (or combination thereof) they desire, so having a
test for syntax can be necessary.

Furthermore, not every
compiler implements a given attribute with the same set of syntaxes
(such as dllexport, which is implemented in gcc as both a GNU-style
and an MS-style attribute, but it only an MS-style attribute in
clang).

OK - this is what I'm interested in, but on further consideration I think
there's an even stronger requirement:

For the has_feature per-syntax checking to be useful, we would have to be in
a world in which two compilers (including different versions of the same
compiler) support the same attribute in non-overlapping syntaxes.

Anyone trying to write portable code isn't going to write:

#if __has_attribute(__attribute__((dllexport)))
  #define DLLEXPORT __attribute__((dllexport))
#elif __has_attribute(declspec(dllexport))
  #define DLLEXPORT declspec(dllexport)
#else
  #define DLLEXPORT
#endif

They're just going to use the common subset that all compiler support
(because generally these attributes have been implemented for compatibility
with other compilers, yes?), thus just preferring the MS syntax in all
cases.

One difference would be that having specific syntax feature detection would
allow safe fallback - if someone had written the dllexport with GCC syntax
using this new feature then on Clang it would've silently not exported (do
people actually ever want that? For some attributes there's a logical
fallback to just not use the attribute, dllexport/import doesn't seem to be
one of those - but that's an aside) - whereas without the syntax-specific
check you'd get an error and need to update the attribute syntax used in the
DLLEXPORT macro to the one that's common between GCC and Clang (& whatever
else).

Even in situations where the compiler *does* implement all of
the syntaxes consistently, it can be beneficial to know which syntax
you are referring to within the context of __has_attribute because
attribute placement is different between varying attribute syntaxes.

Again, this knowledge would be gained through explicit compiler
documentation (as any other language feature or language extension) - not
necessarily meriting a compile-time query system.

Consider, for instance, a vendor with pluggable attributes (which is
something clang could definitely make use of). The vendor may not have
the documentation for the plugin attributes, and discoverability would
be important because the attribute can be written different ways with
varying syntaxes based on each pluggable attribute.

Also, as I mentioned above, the same argument could be made for any of
the feature test macros. Saying "but there's documentation" is not a
compelling argument to me.

Does that clear things up, or am I still not understanding your concerns?

We're closer on the concerns, but I'm still not quite understanding the
justification.

A feature request was filed asking for improved behavior, which was
discussed and expanded upon by others, then designed and implemented
by me. So it can be stated that several people felt there's a
justification for this incremental improvement, and I've tried my best
to explain reasons why this is justified.

Do you have technical concerns about the way it is designed or implemented?

~Aaron

> That's good news -- thanks for confirming.
>
> The feature detection macro itself will still need to have a different
name
> (or some other mechanism) so it can be used compatibly with existing
clang
> deployments, because _has_attribute() currently emits a parse error
instead
> of gracefully returning 0 when passed the new argument syntax:
>
> tmp/attr2.cpp:1:5: error: builtin feature check macro requires a
> parenthesized identifier
> #if __has_attribute(__attribute__((weakref)))
> ^

Good catch. Unfortunately, __has_attribute is really the best
identifier for the macro, so I am loathe to let it go.

Due to the current design of __has_attribute, we can't get away with "
magic" by expanding the non-function-like form into a value that could
be tested. So we would really have to pick a new name if we are
worried about this.

Suggestions on the name are welcome.

Ok, I'll bite:

__has_attribute_written_as([[foo]])
__has_attribute_syntax([[foo]])
__has_attribute_spelling([[foo]])

-- Sean Silva

I kind of like __has_attribute_syntax, truth be told.

Thank you for the suggestions!

~Aaron

    > That's good news -- thanks for confirming.
    >
    > The feature detection macro itself will still need to have a
    different name
    > (or some other mechanism) so it can be used compatibly with
    existing clang
    > deployments, because _has_attribute() currently emits a parse
    error instead
    > of gracefully returning 0 when passed the new argument syntax:
    >
    > tmp/attr2.cpp:1:5: error: builtin feature check macro requires a
    > parenthesized identifier
    > #if __has_attribute(__attribute__((weakref)))
    > ^

    Good catch. Unfortunately, __has_attribute is really the best
    identifier for the macro, so I am loathe to let it go.

    Due to the current design of __has_attribute, we can't get away with "
    magic" by expanding the non-function-like form into a value that could
    be tested. So we would really have to pick a new name if we are
    worried about this.

    Suggestions on the name are welcome.

Ok, I'll bite:

__has_attribute_written_as([[foo]])
__has_attribute_syntax([[foo]])
__has_attribute_spelling([[foo]])

Another possibility:

__has_any_attribute([[foo]])

The silver lining to any one of these names is that they describe the new semantics more clearly without overloading the existing feature macro.

With the naming and forward compatibility changes, the proposal appears to pass the "can we use it in LLVM Compiler.h" sanity check with flying colours.

As for the question of what to do with the old __has_attribute, ~400 uses show up in an Ohloh code search and I'd be concerned to deprecate the present usage without strong reason.

Instead of deprecation and code churn, how about restricting and shoring up the old semantics to match actual usage in the wild? All uses I've seen on Ohloh so far appear to be checking for GNU attributes only.

It sounds like we're getting close to a plan of action.

Alp.