Quuxplusone / LLVMBugzillaTest

0 stars 0 forks source link

__has_cpp_attribute is 1 but warning is printed #32490

Open Quuxplusone opened 7 years ago

Quuxplusone commented 7 years ago
Bugzilla Link PR33518
Status NEW
Importance P enhancement
Reported by Thiago Macieira (thiago@kde.org)
Reported on 2017-06-19 16:19:48 -0700
Last modified on 2021-11-09 06:14:33 -0800
Version trunk
Hardware PC Linux
CC aaron@aaronballman.com, barry.revzin@gmail.com, blitzrakete@gmail.com, dgregor@apple.com, erik.pilkington@gmail.com, jyknight@google.com, llvm-bugs@lists.llvm.org, richard-llvm@metafoo.co.uk, victor.dyachenko@protonmail.com
Fixed by commit(s)
Attachments
Blocks
Blocked by
See also
In the following source code:

#if __has_cpp_attribute(nodiscard)
[[nodiscard]]
#endif
int f()
{
    return 1;
}

If compiled with:
 clang -std=c++11 -Wc++1z-extensions
 (or -std=c++14)

Will produce the warning:
 warning: use of the 'nodiscard' attribute is a C++1z extension [-Wc++1z-extensions]

The compiler should not advertise the availability of a feature it will print a
warning for, if used.

Compatibility: GCC does have __has_cpp_attribute(nodiscard) > 0 even in C++11
mode, but it (currently) no equivalent warning switch.
Quuxplusone commented 7 years ago

Ping. We now have users complaining about not being able to compile their own applications (-Werror in effect) due to this. See https://bugreports.qt.io/browse/QTBUG-61840

Quuxplusone commented 7 years ago
(In reply to Thiago Macieira from comment #0)
> The compiler should not advertise the availability of a feature it will
> print a warning for, if used.

It's not clear there's a good answer here.

1) We do not generally consider it reasonable for -W flags to affect the
meaning of code, so the result of __has_cpp_attribute should ideally not depend
on which -W flags were actually passed.

2) It would degrade the experience of other users of __has_cpp_attribute for us
to say "no" for this attribute merely because someone *could* use -Werror=c++1z-
extensions.

3) Even if we stop advertising the existence of this attribute in C++11,
someone could still use -Werror=c++14-compat when building in C++1z mode, and
get an error because they're using a feature that wasn't part of C++14. (We
don't actually diagnose "attributes from the future" yet, and won't start to do
so unless someone comes up with a very good argument for it, but it's still
informative to think about cases like this.)

Here's one possible workaround:

#if __has_cpp_attribute(nodiscard) <= __cplusplus
[[nodiscard]]
#endif

But maybe we should accept the loss in point 2. Aaron, thoughts?

At the very least, we could move this warning into its own warning group so
that users can turn on -Wc++1z-extensions but not this part. I'm also not
convinced that this should be an "Extension" warning, since a conforming C++11
/ C++14 implementation is allowed to support additional nonstandard attributes.
Quuxplusone commented 7 years ago
> Here's one possible workaround:
>
> #if __has_cpp_attribute(nodiscard) <= __cplusplus
> [[nodiscard]]
> #endif

We thought about that. But what happens if a new edition of the standard
slightly modifies the behaviour of [[nodiscard]] thus requirnig bump in the
version number? This code would disable the functionality for C++17 code.

Maybe instead we ought to know it was added in C++17 and write instead:

#if __cplusplus > 201402L && __has_cpp_attribute(nodiscard)

It wouldn't fix -Wc++14-compat, but that warning is not enabled by default. And
besides, if you want to be compatible with C++14, why would you be compiling in
C++1z mode?
Quuxplusone commented 7 years ago
(In reply to Thiago Macieira from comment #3)
> And besides, if you want to be compatible with C++14, why would you be
> compiling in C++1z mode?

There are various reasons, but it's usually because you have some larger
codebase that you want to build as C++1z, and there's some portion of it that
you want to keep as valid C++14 for now (and perhaps you're concerned about ABI
differences between the two, or you use libraries that expose different
interfaces in the different modes, etc). Or you want to use C++1z stdlib
features but aren't ready to generally start using C++1z language features.

That said... I'm increasingly thinking that we should simply remove the "...
attribute is a C++1z extension" warning. We don't warn on use of any of the
supported [[clang:: or [[gnu:: attributes, so why should we warn on supported
un-namespaced attributes? They're both valid implementation extensions, after
all.
Quuxplusone commented 7 years ago
(In reply to Richard Smith from comment #4)
> That said... I'm increasingly thinking that we should simply remove the "...
> attribute is a C++1z extension" warning. We don't warn on use of any of the
> supported [[clang:: or [[gnu:: attributes, so why should we warn on
> supported un-namespaced attributes? They're both valid implementation
> extensions, after all.

It's a fine line that we may want to walk on another side of. I don't have a
strong feeling one way or the other yet, beyond: whatever we do, I think it
should be consistently applied to all standards-based attributes in the future
as well.

On the one hand, it is an implementation extension and not telling users about
it makes their code less portable to other compiler vendors, which is valuable
for some people. On the other hand, the concerns raised here are compelling.

I find the lack of diagnostic for [[vendor:: attributes to be reasonable
because the mere presence of the vendor namespace is an obvious, visible
indication that this is vendor-specific behavior. That's less clear in the case
of nodiscard.

What about adding -Wc++1*-attribute-extensions as a member of the extensions
group, so you can control these attribute extension diagnostics with finer
granularity?
Quuxplusone commented 7 years ago

Another suggestion: __has_cpp_attribute(nodiscard) returns 0 in -std=c++14, but non-zero under -std=gnu++14. Anyone wishing to check for portability to other compilers needs to disable the extensions anyway.

Quuxplusone commented 7 years ago

We need a direction on what to do. Is Clang's behaviour going to change? Or should we just blacklist the [[nodiscard]] attribute with Clang?

Quuxplusone commented 7 years ago
(In reply to Thiago Macieira from comment #7)
> We need a direction on what to do. Is Clang's behaviour going to change? Or
> should we just blacklist the [[nodiscard]] attribute with Clang?

https://codereview.qt-project.org/200638 - Blacklist use of [[nodiscard]] with
Clang

If this happens again for other attributes without further guidance from Clang
developers, we'll blacklist the use of __has_cpp_attribute instead.
Quuxplusone commented 7 years ago
(In reply to Thiago Macieira from comment #7)
> We need a direction on what to do. Is Clang's behaviour going to change? Or
> should we just blacklist the [[nodiscard]] attribute with Clang?

As stated in the thread, we've not decided what is the best change to make
here. Until we decide that, Clang's behavior isn't going to change. Clang's
current behavior matches what SD-6 recommends in terms of how we handle
__has_cpp_attribute.

I think your suggestion of using:

#if __cplusplus > 201402L && __has_cpp_attribute(nodiscard)

is possibly the best solution for you in the short term. Long term, I'm
slightly leaning towards a new extensions warning group for finer-grained
control.
Quuxplusone commented 5 years ago
C:\>clang++ --version
clang version 8.0.0 (tags/RELEASE_800/final)
Target: x86_64-pc-windows-msvc
Thread model: posix
InstalledDir: c:\opt\LLVM-8\bin

clang++ -std=c++14 -pedantic-errors -Wall

call produces error

error: use of the 'nodiscard' attribute is a C++17 extension [-Werror,-Wc++17-
extensions]

because __has_cpp_attribute(nodiscard) returns true.

Please make it return false when C++14/11/98 mode is used
Quuxplusone commented 5 years ago

Or otherwise don't make its usage an error.

Claiming that it is available for usage and banning its usage at the same time looks like schizophrenia

Quuxplusone commented 5 years ago
Yes, we absolutely should not reject this under -pedantic-errors; the code is
conforming.

(In reply to Aaron Ballman from comment #5)
> What about adding -Wc++1*-attribute-extensions as a member of the extensions
> group, so you can control these attribute extension diagnostics with finer
> granularity?

What about that approach, but don't include the warnings in -Wc++xy-extensions
and convert them from Extension to Warning, DefaultIgnore? (And I'd call the
new warning just -Wc++xy-attributes -- or maybe just add one warning group -
Wfuture-attributes or similar.)
Quuxplusone commented 3 years ago

_Bug 50046 has been marked as a duplicate of this bug._

Quuxplusone commented 3 years ago

(In reply to Richard Smith from comment #12)

Yes, we absolutely should not reject this under -pedantic-errors; the code is conforming.

Er, is that what -pedantic-errors is for? We document it as mapping extension diagnostics to errors. This is an extension, so rejecting the code sounds like exactly what the user asked for.

(In reply to Aaron Ballman from comment #5)

What about adding -Wc++1*-attribute-extensions as a member of the extensions group, so you can control these attribute extension diagnostics with finer granularity?

What about that approach, but don't include the warnings in -Wc++xy-extensions and convert them from Extension to Warning, DefaultIgnore? (And I'd call the new warning just -Wc++xy-attributes -- or maybe just add one warning group -Wfuture-attributes or similar.)

I've been looking into this again and the part that gives me pause is the idea that the -Wc++xy-extensions warning does not include these as extensions when that's precisely what they are. As a user, I want one warning flag that tells me that my code isn't portable for some given standard version and I currently have that flag. I'm more comfortable giving users a way to opt out of the extension warnings they don't care about than I am asking users to remember multiple warning groups to opt into the full set of extension warnings. (This is a general preference, not specific to attributes.)

I think it's a better approach for users who don't want to be told about attribute extensions to use a command like clang -std=c++whatever -Wc++xy-extensions -Wno-c++xy-attribute-extensions foo.cpp because the alternative is users thinking they've enabled extension warnings when they haven't (which is much harder for people to spot).

Quuxplusone commented 3 years ago

FWIW, I originally tried implementing Richard's approach and I really wasn't happy with the change in diagnostic behavior it exposed in our tests. So I made https://reviews.llvm.org/D113115 based on my approach instead, and we can debate the merits on the review.

Quuxplusone commented 3 years ago

ISTM that for attributes like nodiscard -- which has no required effect specified per the standard, and has no effect on compilation beyond diagnostics, there is no reason to warn about it, under any flag.

According to the standard, compilers should ignore unknown attributes, and the attribute has no actual effect on anything. So it nominally doesn't make your code non-portable to use it unconditionally.

Of course, in practice, compilers warn about unknown attributes, so in that way, it may be non-portable, if you use -Werror.

Even so, I'm not sure that issuing a warning simply to say that you're using a feature which might issue a warning on some different compiler makes sense?

Other attributes however seem more critical -- e.g. [[no_unique_address]]. ISTM we likely do want to warn about that one.

Quuxplusone commented 3 years ago

By the letter of the standard, all attributes are ignorable and a compliant compiler can simply implement the known ones as no-ops. Up until C++14, only known attributes were required; prior to that, the compiler was correct in diagnosing unknown attributes, even though all it had to do to be compliant was to ignore it.

For that and other reasons, [[no_unique_address]] should never have been an attribute. It's just wrong. It's fine for an ABI to define that the implementation of the NUA is a no-op, but all the compilers supporting that ABI must implement it and do the exact same thing. There's a reason why C++11 defined alignas as a keyword attribute, not a [[ ]] attribute (which was the first suggestion).

Anyway, the point of this report is that the compiler is saying the attribute is known, but then complains it's an extension when I use it. This is not about having extension attributes. This is not about having warnings about using extensions and therefore making the code non-portable. This is about __has_cpp_attribute saying the attribute is supported, but proceeding to complain it's an extension.

There are probably lots of valid reasons why a warning is legitimate for know attributes (such as being used where it shouldn't be, being ill-advised, deprecated, whatever), but being an extension is not one of them. Especially when the extension was enabled despite using a standards-strict compilation mode and the code in question is actively trying to be portable by checking if the standard attribute is actually supported.

Quuxplusone commented 3 years ago

(In reply to James Y Knight from comment #16)

ISTM that for attributes like nodiscard -- which has no required effect specified per the standard, and has no effect on compilation beyond diagnostics, there is no reason to warn about it, under any flag.

In practice, software that tries to port to different compilers has different compilation paths all the time (thanks to conditional macros, different SFINAE tricks, compiler divergence, etc). So knowing that your [[noreturn]] attribute may not be honored is useful information to know before starting a porting project. For example, it may cause you to add additional test coverage before starting a large porting project to ensure that you still have some degree of assurance of correctness for compilers that don't honor the attribute in that language mode.

But also, this is a way in which programmers are alerted they're using an extension when they might be totally unaware of it. As a concrete example, the LLVM code base requires C++14, so knowing that [[nodiscard("oops")]] is supported but only as a Clang extension is useful to get a diagnostic for, rather than waiting for the CI pipeline to fail -Werror because some other compiler doesn't support that form in C++14 mode.

According to the standard, compilers should ignore unknown attributes, and the attribute has no actual effect on anything. So it nominally doesn't make your code non-portable to use it unconditionally.

[[no_unique_address]] complicates that considerably because "has no actual effect" isn't precisely accurate. The bar is "a correct program remains correct in the absence of the attribute", and [[no_unique_address]] meets that bar, but it still obviously has effects.

Of course, in practice, compilers warn about unknown attributes, so in that way, it may be non-portable, if you use -Werror.

Even so, I'm not sure that issuing a warning simply to say that you're using a feature which might issue a warning on some different compiler makes sense?

We regularly warn about portability issues already, so I'm a bit confused. We have a bunch of extension warnings ("foo is a Clang extension"), but we also have ones where we say "clang accepts this and GCC will reject it" (like adding calling convention attributes in a type position rather than a declaration position), etc. Some of these are on by default diagnostics, others have to be opted into, but we have quite a bit of portability-related diagnostics already. -Wc++xy-extensions is off by default, but in this case, the user explicitly opted into this set of warnings.

Other attributes however seem more critical -- e.g. [[no_unique_address]]. ISTM we likely do want to warn about that one.

Yup! And I'm not going to make per-attribute decisions here.

(In reply to Thiago Macieira from comment #17)

Anyway, the point of this report is that the compiler is saying the attribute is known, but then complains it's an extension when I use it. This is not about having extension attributes. This is not about having warnings about using extensions and therefore making the code non-portable. This is about __has_cpp_attribute saying the attribute is supported, but proceeding to complain it's an extension.

This is a fundamental misunderstanding. has_cpp_attribute does not tell you "you won't be warned when using this attribute", it only informs you whether the compiler knows about the attribute or not. It's invalid to expect has_cpp_attribute means "using this attribute will not diagnose." e.g., https://godbolt.org/z/e59PKhz56

The compiler does not warn by default in this case, the user has to explicitly opt into these warnings. So the correct fix, to me, is to give the user better granularity on the warnings they want. In this case, you want extension warnings, you don't care about attribute extensions, and Clang can't support that today. I want extension warnings, I care about attribute extensions, I don't want to lose that. (In fact, I'm comfortable saying that as attribute code owner, I require there to be some way to alert programmers that they're using attribute extensions. It doesn't have to be the way I wrote the patch, but I'm not willing to lose the ability to know in general that Clang is supporting a construct as a conforming extension in a given language mode.)

There are probably lots of valid reasons why a warning is legitimate for know attributes (such as being used where it shouldn't be, being ill-advised, deprecated, whatever), but being an extension is not one of them. Especially when the extension was enabled despite using a standards-strict compilation mode and the code in question is actively trying to be portable by checking if the standard attribute is actually supported.

And the standard attribute is actually supported but it is still an extension to do so. You're getting the diagnostics you explicitly asked the compiler for.

Quuxplusone commented 3 years ago

All I am asking of the LLVM team here is: what is the proper "incantation" to determine that I can use a given attribute "in good standing" without producing a warning under -Wextra? "In Good Standing" to mean here used in the proper place, applied to the proper statement/declaration, and isn't ill-advised or deprecated.

It's been suggested that I check cplusplus version alongside the has_cpp_attribute. That's fine as a suggestion. I'd like a confirmation.

I don't mind warnings not enabled by -Wextra, including -Weverything (that's not something I understand is recommended that anyone use, except to debug clang itself).

Quuxplusone commented 3 years ago
(In reply to Thiago Macieira from comment #19)
> All I am asking of the LLVM team here is: what is the proper "incantation"
> to determine that I can use a given attribute "in good standing" without
> producing ​a warning under -Wextra?

This warning _isn't_ enabled by -Wall or -Wextra, so if that's all you care
about, you shouldn't need to worry. It is enabled by -pedantic -- which someone
else mentioned -- perhaps you're using that, too?

To the second half of the question, I'm not sure there's really a great answer
at the moment. You could e.g. do something like:
#if __has_cpp_attribute(nodiscard) && __cplusplus >= 201703L
or,
#if __has_cpp_attribute(nodiscard) && (!defined(__clang__) || __cplusplus >=
201703L)

(In reply to Aaron Ballman from comment #18)
> But also, this is a way in which programmers are alerted they're using an
> extension when they might be totally unaware of it. As a concrete example,
> the LLVM code base requires C++14, so knowing that [[nodiscard("oops")]] is
> supported but only as a Clang extension is useful to get a diagnostic for,
> rather than waiting for the CI pipeline to fail -Werror because some other
> compiler doesn't support that form in C++14 mode.

This is a convincing argument, especially when the warnings are specifically
requested via "-Wc++NN-extensions". I'm convinced that your patch to split the
warning groups is a good idea.

So, the main question remaining in my mind is when these warnings should be
enabled. I think it may make sense to have these newly-split-off -Wc++NN-
attribute-extensions warnings _not_ be enabled by -pedantic. The other
extensions we warn about are actually invalid syntax in earlier language
versions. However, any attribute whatsoever is explicitly intended to be valid
in old language versions.

To reply to a previous comment,
> Er, is that what -pedantic-errors is for? We document it as mapping
> extension diagnostics to errors. This is an extension, so rejecting the
> code sounds like exactly what the user asked for.

But, using an attribute not defined by the C++14 spec isn't really an
extension, -- the spec explicitly allows for that. At the very least, it's not
an extension in the same way as "float x = 0x1p+1" in C++14 is -- that's
actually invalid syntax in old versions.
Quuxplusone commented 3 years ago
(In reply to James Y Knight from comment #20)
> This warning _isn't_ enabled by -Wall or -Wextra, so if that's all you care
> about, you shouldn't need to worry. It is enabled by -pedantic -- which
> someone else mentioned -- perhaps you're using that, too?

Thanks, I might have missed this detail. The report was because we produced the
arning in one of our headers and a user asked that we clean it up. I don't
remember if the policy that "we don't guarantee warning-clean above -Wextra"
was in place back in 2017 either.

> To the second half of the question, I'm not sure there's really a great
> answer at the moment. You could e.g. do something like:
> #if __has_cpp_attribute(nodiscard) && __cplusplus >= 201703L
> or,
> #if __has_cpp_attribute(nodiscard) && (!defined(__clang__) || __cplusplus >=
> 201703L)

I'd rather not have the clang-specific check there if I can help it. If the
first of the two options works, I'll prefer it.

> To reply to a previous comment,
> > Er, is that what -pedantic-errors is for? We document it as mapping
> > extension diagnostics to errors. This is an extension, so rejecting the
> > code sounds like exactly what the user asked for.
>
> But, using an attribute not defined by the C++14 spec isn't really an
> extension, -- the spec explicitly allows for that. At the very least, it's
> not an extension in the same way as "float x = 0x1p+1" in C++14 is -- that's
> actually invalid syntax in old versions.

Clang probably inherited -pednatic and -pednatic-errors from GCC, which had
them way back when code was much less standardised (particularly with pre-ANSI
C) and therefore the compiler couldn't be pedantic about following the
standard. I don't know if it actually changed parsing or semantics with those
options. That might also be why they were added as -pedantic and not -Wpedantic
from the start (see also -ansi).
Quuxplusone commented 3 years ago
(In reply to James Y Knight from comment #20)
> This is a convincing argument, especially when the warnings are specifically
> requested via "-Wc++NN-extensions". I'm convinced that your patch to split
> the warning groups is a good idea.

Thanks!

> So, the main question remaining in my mind is when these warnings should be
> enabled. I think it may make sense to have these newly-split-off
> -Wc++NN-attribute-extensions warnings _not_ be enabled by -pedantic. The
> other extensions we warn about are actually invalid syntax in earlier
> language versions. However, any attribute whatsoever is explicitly intended
> to be valid in old language versions.

Hmm, I don't think I agree that -pedantic is only about extensions that are
invalid syntax in earlier language versions. For example, we give extension
warnings on pointer comparisons (https://godbolt.org/z/qMaqYfqj3) that are
about semantics, not syntax. -pedantic is documented in Clang to turn extension
diagnostics into warnings (and -pedantic-errors is documented to turn extension
diagnostics into errors). https://clang.llvm.org/docs/UsersManual.html#options-
to-control-error-and-warning-messages Because these are extensions (not
standards-defined constructs) in the requested language mode, I think -pedantic
should continue to trigger them.

> To reply to a previous comment,
> > Er, is that what -pedantic-errors is for? We document it as mapping
> > extension diagnostics to errors. This is an extension, so rejecting the
> > code sounds like exactly what the user asked for.
>
> But, using an attribute not defined by the C++14 spec isn't really an
> extension, -- the spec explicitly allows for that. At the very least, it's
> not an extension in the same way as "float x = 0x1p+1" in C++14 is -- that's
> actually invalid syntax in old versions.

It's implementation-defined what it means to support an attribute that's not
specified by a given language standard, so the spec explicitly allows for us to
do anything we want. (Also, diagnostics are almost wholly in the realm of QoI
anyway.)

I certainly believe this is an extension, at least in the spirit of what "warn
on extensions" is trying to accomplish. C++N-1 does not define the semantics of
an attribute from C++N, which can have the same effects as actually invalid
syntax. For example, Clang has a policy that all ignored attributes are
diagnosed; if another compiler has a similar policy, it means that -pedantic on
your Clang source base will tell you about -Werror problems you'll hit in that
other implementation. By my understanding, that's basically the whole goal to -
pedantic. [[no_unique_address]] also throws a bit of a wrench into things in
that whether the implementation supports it or not can have noticeable semantic
effects.

At the same time, I see exactly where people are coming from regarding that the
standard does not require that we diagnose unknown attributes and so it feels a
bit weird to diagnose under -pedantic when that's a grouping for "persnickety
stuff the standard requires us to warn about". These are a bit different from
purely syntactic extensions, like you pointed out. But I don't know that we
want to split the hair that finely and have different "levels" of extensions
where some are controlled by -pedantic and some aren't. As an example, we have
a diagnostic that complex numbers are an extension in a freestanding
implementation; but freestanding implementations are allowed to include
whatever additional headers they want so this is a similar situation to the one
we have with attributes. I think that if we wanted to make a distinction here,
someone would have to look through our extension diagnostics and decide which
ones go into what warning group. But then I wouldn't yet know what metric to
use to decide whether to include something as a pedantic extension or a
nonpedantic extension.

I think the most conservative approach is: leave them as extension diagnostics
(so they're still enabled via -pedantic), explore what distinctions we feel we
need to make between extensions and pedantic, and come up with a plan from
there. For example, one path we could take is to add a -Wportability grouping
that is a superset of -pedantic and things like attribute extension
warnings/complex in freestanding/etc can be under -Wportability but left out of
-pedantic. However, I can live with the status quo of -pedantic warning about
attribute extensions for a while longer.
Quuxplusone commented 3 years ago

I believe the intent of -pedantic is roughly to: 'diagnose syntax/operations which are not allowed by the standard, but which the compiler accepts anyhow -- even though it is outside of the normal bounds reserved for the implementation by the standard.'

That's why extensions like attribute and typeof are not diagnosed. They're certainly not portable, but, because they're explicitly reserved-for-implementation-extensions identifiers, are considered OK.

Other features, e.g. your example of C code comparing a pointer to an integer or my example of "0x1p+1" are not in an explicitly-reserved-for-implementation category -- that's something which is not permitted by the standard yet is accepted anyways (under the rationale that it doesn't change the behavior of correct code, so it's OK to do so). It is that category which gets pedantically warned about.

I don't think -pedantic is -- or should be -- intended to diagnose on code that is 100% valid, standards-compliant, and correct, but which might trigger a warning on another compiler.

To me, attribute warnings fall into the first category: an "expected" implementation extension point.

Quuxplusone commented 3 years ago
(In reply to James Y Knight from comment #23)
> I believe the intent of -pedantic is roughly to: 'diagnose syntax/operations
> which are not allowed by the standard, but which the compiler accepts anyhow
> -- even though it is outside of the normal bounds reserved for the
> implementation by the standard.'
>
> That's why extensions like __attribute__ and __typeof__ are not diagnosed.
> They're certainly not portable, but, because they're explicitly
> reserved-for-implementation-extensions identifiers, are considered OK.

Hmm, I think I have a different viewpoint. __attribute__ and __typeof__ are not
diagnosed because they're hard to accidentally make use of without realizing
you're using an extension (due to the spelling of their identifiers). The same
is not true with [[likely]] in C++11 mode -- it's quite easy to write that and
have no idea what you're using is an extension. And knowing whether the
attribute has an effect is something we've traditionally considered to be
Extremely Important in Clang (this is why we diagnose all unknown attributes).

FWIW, I think attributes meet your definition, but it requires some squinting
because of "allowed" (anything undefined according to the standard is "allowed"
to be defined by the implementation, so that muddies things). [[likely]] in
C++11 mode is not defined by the standard, but Clang accepts anyhow. As with
all extensions, the definition of what it means to accept this code is outside
the bounds of the standard, but the standard gives implementations the right to
define that behavior. The only difference between [[likely]] in C++11 and
__attribute__(()) is that if an implementation does not define the behavior for
[[likely]] in C++11, it cannot reject translation of the program (because the
standard mandates the unknown attribute be ignored), but it can reject
translation of a program including __attribute__ because there is no explicit
mandate to ignore that.

> Other features, e.g. your example of C code comparing a pointer to an
> integer or my example of "0x1p+1" are not in an
> explicitly-reserved-for-implementation category -- that's something which is
> not permitted by the standard yet is accepted anyways (under the rationale
> that it doesn't change the behavior of correct code, so it's OK to do so).
> It is that category which gets pedantically warned about.
>
> I don't think -pedantic is -- or should be -- intended to diagnose on code
> that is 100% valid, standards-compliant, and correct, but which might
> trigger a warning on another compiler.

This is an argument I find compelling. But at the same time, 1) the documented
status quo in Clang is that -pedantic diagnoses extensions and these are
extensions, 2) I need some way to tell me "you're using an extension" because
[[likely]] (et al) is not practically feasible for users to know is an
extension without also seeing the precise build commands, and 3) users should
not require multiple flags to tell them when their code is using facilities
outside of those mandated by the standard and we've traditionally positioned -
pedantic as our "strictly conforming" mode.

For background, the behavior with -pedantic and attributes has existed since at
least Clang 3.7 (2015).
Quuxplusone commented 3 years ago

Btw, one thing that's become abundantly clear to me is that our documentation for -pedantic is woefully lacking (https://clang.llvm.org/docs/UsersManual.html#cmdoption-pedantic). Whatever decisions we make in this area, I think we should also update this part of the documentation once we have some more agreement between us.