Date: Tue, 10 Feb 2026 21:00:48 +0100
On 10/02/2026 17:37, Jason McKesson via Std-Proposals wrote:
> On Tue, Feb 10, 2026 at 11:25 AM Barry Revzin via Std-Proposals
> <std-proposals_at_[hidden]> wrote:
>> On Tue, Feb 10, 2026, 10:13 AM David Brown via Std-Proposals <std-proposals_at_[hidden]> wrote:
>>> On 10/02/2026 16:21, Alejandro Colomar wrote:
>>>> Hi David,
>>>>
>>>> On 2026-02-10T15:47:12+0100, David Brown wrote:
>>>> [...]
>>>>>>> [[comp::attr]]
>>>>>>> Ignorable or non-ignorable according to the implementation (with the
>>>>>>> recommendation that it is ignorable by default but that the compiler provide
>>>>>>> a flag to make it non-ignorable).
>>>>>>>
>>>>>>> [[[comp::attr]]]
>>>>>>> Non-ignorable. If a compiler cannot support this in the manner intended by
>>>>>>> the "comp" compiler, it is a fatal error.
>>>>>>>
>>>>>>> [[(comp::attr)]]
>>>>>>> Ignorable. Compilers are encouraged to provide a warning if they are the
>>>>>>> owner of the "comp" namespace and do not recognise "attr".
>>>>>>>
>>>>>>> [[[comp1::attr1 || comp2::attr2 || ... ]]]
>>>>>>> Non-ignorable. Compilers must support and apply one of these attributes,
>>>>>>> but may choose which. If they cannot support any, it is a fatal error. For
>>>>>>> example, [[[gnu::always_inline || msvc::forceinline]]]
>>>>>>>
>>>>>
>>>>> You did not comment on this syntax, which I think is the most significant
>>>>> new idea in my post. Do you like this idea, or do you have a better
>>>>> alternative?
>>>>
>>>> That feature exists:
>>>>
>>>> #if __has_c_attribute(gnu::packed)
>>>> # define PACKED gnu::packed
>>>> #else if __has_c_attribute(foo::packed)
>>>> # define PACKED foo::packed
>>>> #else
>>>> # error "No support for a packed attribute"
>>>> #endif
>>>>
>>>> [[PACKED]] void f(void);
>>>>
>>>> I agree that || would be nice for this. I'd make it
>>>>
>>>> [[gnu::packed || foo::packed]]
>>>>
>>>> without a third '['
>>>>
>>>
>>> (The third [ was for consistency with user indication that the attribute
>>> should not be ignorable, but that's an orthogonal point.)
>>>
>>>>>
>>>>>>> [[(comp1::attr1 || comp2::attr2 || ... )]]
>>>>>>> The compiler can apply its choice of one of these attributes, but can ignore
>>>>>>> them all.
>>>>>>
>>>>>> I think it's a bad idea to allow programmers to decide about the
>>>>>> ignorability of language features. Ignorability of a feature should be
>>>>>> part of the feature itself. What would it mean to do
>>>>>>
>>>>>> [[(gnu::packed)]]
>>>>>>
>>>>>> ? That's an ABI-breaking attribute, and ignoring it will result in
>>>>>> bugs.
>>>>>>
>>>>>
>>>>> We can't legislate against programmers doing something stupid! And we
>>>>> certainly should not limit their abilities to make useful choices just
>>>>> because some people might do something silly - at least not when it requires
>>>>> an active choice such as this syntax requires. We should of course try to
>>>>> reduce the risk of accidental mistakes (which is a big reason, IMHO, that
>>>>> making "[[no_discard]]" ignorable is a terrible mistake - an accidental
>>>>> misspelling of a language feature should result in an error message, not be
>>>>> quietly discarded).
>>>>>
>>>>> But I think it would be fine for both the C++ standard and compiler
>>>>> documentation for namespace attributes to say that certain attributes cannot
>>>>> be ignored. If that applied to "gnu::packed", then "[[(gnu::packed)]]"
>>>>> would be an error. But programmers should be allowed to mark an attribute
>>>>> like "gnu::cold" as ignorable because it does not affect the semantics of
>>>>> the program in any way.
>>>>>
>>>>>> I prefer keeping all vendor attributes non-ignorable, and close the door
>>>>>> to ignorable vendor attributes. Then, if we want standard non-ignorable
>>>>>> ones, let's just specify a standard "vendor"; that could be the empty
>>>>>> prefix ::, or maybe std::.
>>>>>>
>>>>>
>>>>> There are lots of vendor attributes that can be used today, and that would
>>>>> be safe to ignore. I prefer to say that if an attribute is not ignorable
>>>>> (either because the user has used [[[ ]]], or because the it is documented
>>>>> as never ignorable) then it cannot be ignored by /any/ compiler. That
>>>>> requirement puts a lot of pressure on compiler implementations, and I think
>>>>> it is best to relieve that pressure by allowing attributes to be ignorable
>>>>> when the user knows that is safe.
>>>>
>>>> That feature exists:
>>>>
>>>> #if __has_c_attribute(gnu::cold)
>>>> # define COLD gnu::cold
>>>> #else
>>>> # define COLD
>>>> #endif
>>>>
>>>> [[COLD]] void f(void);
>>>>
>>>> I don't see a need for a new spelling.
>>>> I don't see a need to ignorable attributes.
>>>>
>>>>
>>>> Cheers,
>>>> Alex
>>>>
>>>
>>> While that is all true, it defeats the point of attributes (at least
>>> non-standard attributes) in the first place. After all, why support
>>> [[gnu::cold]] or [[msvc::cold_func]] (if that existed) format when you
>>> could have simply written :
>>>
>>> #if defined(__GNUC__)
>>> # define COLD __attribute__((cold))
>>> #elif defined(_MSC_VER)
>>> # define COLD _declspec(cold_func)
>>> #else
>>> # define COLD
>>> #endif
>>>
>>> COLD void f(void);
>>>
>>> Compiler-check conditional compilation and conditional macro definitions
>>> are horrible. Conditional compilation and macro definitions based on
>>> feature checks are marginally less horrible, but only marginally so.
>>> Both can be very useful, but you don't want to have to use them except
>>> in rare and unusual cases. It is far better to be able to write :
>>>
>>> [[gnu::cold, msvc::cold_func]] void f(void);
>>>
>>> and skip the pre-processor stuff.
>>
>>
>> This right here immediately gets straight to the issue. The only remotely plausible argument for there being any value in ignoring attributes is precisely that: to be able to write code like that and skip the preprocessor stuff.
>>
>> The problem is, it comes with it the very big cost that the compiler of course has no way to differentiate between the cases where you might conceivably want it to ignore... and the cases where you just wrote the wrong thing by accident and it's a bug. Even in this case where you might think is easy, just ignore vendored attributes in a different namespace, what if I wrote mvsc::meow instead of msvc::meow?
>>
>> As I wrote in my blog (https://brevzin.github.io/c++/2025/03/25/attributes/), a solution that would actually be useful here would be allow users to explicitly declare attributes they want "ignored" - which still isn't ignoring attributes (a design strategy that has clear negative value), simply explicitly declaring them to be no-ops. That would still require the preprocessor stuff, but only once per attribute, and the usage would have the good, macro-free syntax.
>>
>> Attributes are a great feature for adding new functionality without having to introduce new (uglier) keywords or grammar.
>>
>> Or, at least, they could be, if we just stop pre-emptively crippling them and pretending they're glorified comments.
>
> Why [[do]] we want [[to read]] code [[that]] looks [[like this]]? Why
> is this a good thing for the language?
>
> Attribute syntax is very eye-poking and makes code harder to read. Why
> do we want to proliferate this everywhere? If we need a way to make
> new keywords without impacting code, then we should add that as core
> functionality.
C++ code already has plenty of the most astounding eye-watering mess in
its syntax and names, "contextual keywords" and "identifiers with
special meanings". Fortunately, most of it is rarely used in user-level
code, but exists so that library writters can give us efficient and
powerful libraries. But the attribute syntax is merely a blip on this
landscape - it hardly counts as "hard to read" in a language that
considers [](){}() as valid code. IMHO, it can be clearer to read code
that uses [[foo]] rather than inventing steadily more pseudo-keywords
that readers will be unsure as to whether they are keywords or
identifiers, because the interpretation of the same written word varies
depending on the context.
I don't think we want to see a lot of attributes in code - they should
be for relatively rare things. But I /do/ think they are often better
than the alternatives.
Still, beauty is in the eye of the beholder, as is readability. And it
is not easy to judge how things will look in real code after a feature
has been added to the language and used in practice.
>
> People often talk about how the `co_await` and `co_return` keywords
> look bad. Seing `[[await]]` and `[[return]]` wouldn't be any better.
> Not only are they one keystroke longer, they poke you in the eye in a
> way that just text with underscores does not.
>
> Attributes are only a "great feature for adding new functionality" if
> we ignore how they make the code look. I wasn't there for any of the
> conversations for attribute syntax, but wasn't one of the agreements
> made with the syntax that it *not* be used as a keyword replacement?
> Which is why it wasn't used for alignas, override, and final?
>
> This feels a bit like a deal was worked out that people are now trying
> to renege on because it's convenient to do so.
> On Tue, Feb 10, 2026 at 11:25 AM Barry Revzin via Std-Proposals
> <std-proposals_at_[hidden]> wrote:
>> On Tue, Feb 10, 2026, 10:13 AM David Brown via Std-Proposals <std-proposals_at_[hidden]> wrote:
>>> On 10/02/2026 16:21, Alejandro Colomar wrote:
>>>> Hi David,
>>>>
>>>> On 2026-02-10T15:47:12+0100, David Brown wrote:
>>>> [...]
>>>>>>> [[comp::attr]]
>>>>>>> Ignorable or non-ignorable according to the implementation (with the
>>>>>>> recommendation that it is ignorable by default but that the compiler provide
>>>>>>> a flag to make it non-ignorable).
>>>>>>>
>>>>>>> [[[comp::attr]]]
>>>>>>> Non-ignorable. If a compiler cannot support this in the manner intended by
>>>>>>> the "comp" compiler, it is a fatal error.
>>>>>>>
>>>>>>> [[(comp::attr)]]
>>>>>>> Ignorable. Compilers are encouraged to provide a warning if they are the
>>>>>>> owner of the "comp" namespace and do not recognise "attr".
>>>>>>>
>>>>>>> [[[comp1::attr1 || comp2::attr2 || ... ]]]
>>>>>>> Non-ignorable. Compilers must support and apply one of these attributes,
>>>>>>> but may choose which. If they cannot support any, it is a fatal error. For
>>>>>>> example, [[[gnu::always_inline || msvc::forceinline]]]
>>>>>>>
>>>>>
>>>>> You did not comment on this syntax, which I think is the most significant
>>>>> new idea in my post. Do you like this idea, or do you have a better
>>>>> alternative?
>>>>
>>>> That feature exists:
>>>>
>>>> #if __has_c_attribute(gnu::packed)
>>>> # define PACKED gnu::packed
>>>> #else if __has_c_attribute(foo::packed)
>>>> # define PACKED foo::packed
>>>> #else
>>>> # error "No support for a packed attribute"
>>>> #endif
>>>>
>>>> [[PACKED]] void f(void);
>>>>
>>>> I agree that || would be nice for this. I'd make it
>>>>
>>>> [[gnu::packed || foo::packed]]
>>>>
>>>> without a third '['
>>>>
>>>
>>> (The third [ was for consistency with user indication that the attribute
>>> should not be ignorable, but that's an orthogonal point.)
>>>
>>>>>
>>>>>>> [[(comp1::attr1 || comp2::attr2 || ... )]]
>>>>>>> The compiler can apply its choice of one of these attributes, but can ignore
>>>>>>> them all.
>>>>>>
>>>>>> I think it's a bad idea to allow programmers to decide about the
>>>>>> ignorability of language features. Ignorability of a feature should be
>>>>>> part of the feature itself. What would it mean to do
>>>>>>
>>>>>> [[(gnu::packed)]]
>>>>>>
>>>>>> ? That's an ABI-breaking attribute, and ignoring it will result in
>>>>>> bugs.
>>>>>>
>>>>>
>>>>> We can't legislate against programmers doing something stupid! And we
>>>>> certainly should not limit their abilities to make useful choices just
>>>>> because some people might do something silly - at least not when it requires
>>>>> an active choice such as this syntax requires. We should of course try to
>>>>> reduce the risk of accidental mistakes (which is a big reason, IMHO, that
>>>>> making "[[no_discard]]" ignorable is a terrible mistake - an accidental
>>>>> misspelling of a language feature should result in an error message, not be
>>>>> quietly discarded).
>>>>>
>>>>> But I think it would be fine for both the C++ standard and compiler
>>>>> documentation for namespace attributes to say that certain attributes cannot
>>>>> be ignored. If that applied to "gnu::packed", then "[[(gnu::packed)]]"
>>>>> would be an error. But programmers should be allowed to mark an attribute
>>>>> like "gnu::cold" as ignorable because it does not affect the semantics of
>>>>> the program in any way.
>>>>>
>>>>>> I prefer keeping all vendor attributes non-ignorable, and close the door
>>>>>> to ignorable vendor attributes. Then, if we want standard non-ignorable
>>>>>> ones, let's just specify a standard "vendor"; that could be the empty
>>>>>> prefix ::, or maybe std::.
>>>>>>
>>>>>
>>>>> There are lots of vendor attributes that can be used today, and that would
>>>>> be safe to ignore. I prefer to say that if an attribute is not ignorable
>>>>> (either because the user has used [[[ ]]], or because the it is documented
>>>>> as never ignorable) then it cannot be ignored by /any/ compiler. That
>>>>> requirement puts a lot of pressure on compiler implementations, and I think
>>>>> it is best to relieve that pressure by allowing attributes to be ignorable
>>>>> when the user knows that is safe.
>>>>
>>>> That feature exists:
>>>>
>>>> #if __has_c_attribute(gnu::cold)
>>>> # define COLD gnu::cold
>>>> #else
>>>> # define COLD
>>>> #endif
>>>>
>>>> [[COLD]] void f(void);
>>>>
>>>> I don't see a need for a new spelling.
>>>> I don't see a need to ignorable attributes.
>>>>
>>>>
>>>> Cheers,
>>>> Alex
>>>>
>>>
>>> While that is all true, it defeats the point of attributes (at least
>>> non-standard attributes) in the first place. After all, why support
>>> [[gnu::cold]] or [[msvc::cold_func]] (if that existed) format when you
>>> could have simply written :
>>>
>>> #if defined(__GNUC__)
>>> # define COLD __attribute__((cold))
>>> #elif defined(_MSC_VER)
>>> # define COLD _declspec(cold_func)
>>> #else
>>> # define COLD
>>> #endif
>>>
>>> COLD void f(void);
>>>
>>> Compiler-check conditional compilation and conditional macro definitions
>>> are horrible. Conditional compilation and macro definitions based on
>>> feature checks are marginally less horrible, but only marginally so.
>>> Both can be very useful, but you don't want to have to use them except
>>> in rare and unusual cases. It is far better to be able to write :
>>>
>>> [[gnu::cold, msvc::cold_func]] void f(void);
>>>
>>> and skip the pre-processor stuff.
>>
>>
>> This right here immediately gets straight to the issue. The only remotely plausible argument for there being any value in ignoring attributes is precisely that: to be able to write code like that and skip the preprocessor stuff.
>>
>> The problem is, it comes with it the very big cost that the compiler of course has no way to differentiate between the cases where you might conceivably want it to ignore... and the cases where you just wrote the wrong thing by accident and it's a bug. Even in this case where you might think is easy, just ignore vendored attributes in a different namespace, what if I wrote mvsc::meow instead of msvc::meow?
>>
>> As I wrote in my blog (https://brevzin.github.io/c++/2025/03/25/attributes/), a solution that would actually be useful here would be allow users to explicitly declare attributes they want "ignored" - which still isn't ignoring attributes (a design strategy that has clear negative value), simply explicitly declaring them to be no-ops. That would still require the preprocessor stuff, but only once per attribute, and the usage would have the good, macro-free syntax.
>>
>> Attributes are a great feature for adding new functionality without having to introduce new (uglier) keywords or grammar.
>>
>> Or, at least, they could be, if we just stop pre-emptively crippling them and pretending they're glorified comments.
>
> Why [[do]] we want [[to read]] code [[that]] looks [[like this]]? Why
> is this a good thing for the language?
>
> Attribute syntax is very eye-poking and makes code harder to read. Why
> do we want to proliferate this everywhere? If we need a way to make
> new keywords without impacting code, then we should add that as core
> functionality.
C++ code already has plenty of the most astounding eye-watering mess in
its syntax and names, "contextual keywords" and "identifiers with
special meanings". Fortunately, most of it is rarely used in user-level
code, but exists so that library writters can give us efficient and
powerful libraries. But the attribute syntax is merely a blip on this
landscape - it hardly counts as "hard to read" in a language that
considers [](){}() as valid code. IMHO, it can be clearer to read code
that uses [[foo]] rather than inventing steadily more pseudo-keywords
that readers will be unsure as to whether they are keywords or
identifiers, because the interpretation of the same written word varies
depending on the context.
I don't think we want to see a lot of attributes in code - they should
be for relatively rare things. But I /do/ think they are often better
than the alternatives.
Still, beauty is in the eye of the beholder, as is readability. And it
is not easy to judge how things will look in real code after a feature
has been added to the language and used in practice.
>
> People often talk about how the `co_await` and `co_return` keywords
> look bad. Seing `[[await]]` and `[[return]]` wouldn't be any better.
> Not only are they one keystroke longer, they poke you in the eye in a
> way that just text with underscores does not.
>
> Attributes are only a "great feature for adding new functionality" if
> we ignore how they make the code look. I wasn't there for any of the
> conversations for attribute syntax, but wasn't one of the agreements
> made with the syntax that it *not* be used as a keyword replacement?
> Which is why it wasn't used for alignas, override, and final?
>
> This feels a bit like a deal was worked out that people are now trying
> to renege on because it's convenient to do so.
Received on 2026-02-10 20:00:52
