On Wed, Jul 08, 2026 at 08:27:12PM +0200, Jakub Jelinek wrote:
> On Wed, Jul 08, 2026 at 02:08:38PM -0400, Jason Merrill wrote:
> > > --- gcc/testsuite/g++.dg/cpp0x/attr-trivial_abi8.C.jj 2026-07-08
> > > 18:49:01.145455196 +0200
> > > +++ gcc/testsuite/g++.dg/cpp0x/attr-trivial_abi8.C 2026-07-08
> > > 18:49:23.583166926 +0200
> > > @@ -0,0 +1,20 @@
> > > +// { dg-do compile { target c++11 } }
> > > +
> > > +#if __has_cpp_attribute (clang::trivial_abi) != 1
> > > +#error
> > > +#endif
> > > +#if __has_cpp_attribute (gnu::trivial_abi) != 0
> > > +#error
> > > +#endif
> > > +#if __has_cpp_attribute (trivial_abi) != 1
> > > +#error
> > > +#endif
> >
> > This answer seems clearly wrong, since [[trivial_abi]] doesn't work. I'd
> > prefer expecting 0 and xfail.
>
> I know, but unfortunately __has_cpp_attribute and __has_attribute
> behave identically in C++.
> In C __has_attribute (identifier) tests __attribute__((identifier))
> or [[identifier]] support and __has_c_attribute (identifier)
> tests [[identifier]] only and both with scoped attributes test
> [[scope::identifier]].
> But I'm not sure it isn't too late to change this when both C++ forms
> behaved the same way since GCC 5.1, so 11 years in the wild.
>
> There is a way to differentiate what can be accepted as [[identifier]]
> even in C++, if __has_cpp_attribute results in 1, it is the __attribute__
> form, if it is >= 2 (or >= 200809, there is nothing in between), then
> it is [[identifer]].
And it is even documented like that.
The special operator @code{__has_cpp_attribute (@var{operand})} may be used
in @samp{#if} and @samp{#elif} expressions in C++ code to test whether
the attribute referenced by its @var{operand} is recognized by GCC.
@code{__has_cpp_attribute (@var{operand})} is equivalent to
@code{__has_attribute (@var{operand})} except that when @var{operand}
designates a supported standard attribute it evaluates to an integer
constant of the form @code{YYYYMM} indicating the year and month when
the attribute was first introduced into the C++ standard.
The "except that when @var{operand} ... " part is misleading because
__has_attribute behaves exactly like that too.
Looking at clang++, that behaves differently, doesn't allow scoped
attributes in __has_attribute at all (just __has_cpp_attribute and
__has_c_attribute) and __has_cpp_attribute (trivial_abi) is 0
and __has_attribute (trivial_abi) is 1.
Jakub