Date: Tue, 10 Feb 2026 18:36:45 -0500
On Tue, Feb 10, 2026 at 3:00 PM David Brown via Std-Proposals
<std-proposals_at_[hidden]> wrote:
> 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.
Has anyone ever shown confusion as to what "override" after a member
function does? Like, anyone who has seen virtual functions in any
language other than C++ has at least a working understanding of what
that word is doing. So what exactly is the problem?
The users of a language don't care if functionality comes via a formal
keyword or a contextual keyword. What they care about is that they can
read and understand what the language is doing. `[[override]]` is not
easier to read than `override`.
> 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.
What you want, in this moment, doesn't matter. What matters is that
the rule about attributes functionally acts as a *firewall* against
"seeing a lot of attributes in code".
Consider the code under discussion today. Whatever the syntax for
named return values will be, you *will* see it frequently. People are
going to use it a lot, even if they don't really need to because
someone will tell them that they should because it'll make their code
faster.
If you start allowing attributes to be used to do keyword things, then
they *will* be how we do keyword things going forward. So if you want
to allow that, you have to be prepared to see it a lot.
Let's say we start getting into more and more compile-time generative
code mechanics via reflection and reification. As part of that, we
want users to be able to tag functions/classes/members/etc in ways
that the generative code mechanisms can react to. If we use attributes
as the means to do that, then you're going to see attributes
*everywhere*.
To me, the main reason to keep attributes "ignorable" is to prevent
them from being used to do more things and thus to prevent them from
proliferating through code. If you allow them to do more things, they
will have to be used more often, and [[eventually]], all of [[our
code]] is [[going]] to have [[::to(look)]] like this.
<std-proposals_at_[hidden]> wrote:
> 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.
Has anyone ever shown confusion as to what "override" after a member
function does? Like, anyone who has seen virtual functions in any
language other than C++ has at least a working understanding of what
that word is doing. So what exactly is the problem?
The users of a language don't care if functionality comes via a formal
keyword or a contextual keyword. What they care about is that they can
read and understand what the language is doing. `[[override]]` is not
easier to read than `override`.
> 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.
What you want, in this moment, doesn't matter. What matters is that
the rule about attributes functionally acts as a *firewall* against
"seeing a lot of attributes in code".
Consider the code under discussion today. Whatever the syntax for
named return values will be, you *will* see it frequently. People are
going to use it a lot, even if they don't really need to because
someone will tell them that they should because it'll make their code
faster.
If you start allowing attributes to be used to do keyword things, then
they *will* be how we do keyword things going forward. So if you want
to allow that, you have to be prepared to see it a lot.
Let's say we start getting into more and more compile-time generative
code mechanics via reflection and reification. As part of that, we
want users to be able to tag functions/classes/members/etc in ways
that the generative code mechanisms can react to. If we use attributes
as the means to do that, then you're going to see attributes
*everywhere*.
To me, the main reason to keep attributes "ignorable" is to prevent
them from being used to do more things and thus to prevent them from
proliferating through code. If you allow them to do more things, they
will have to be used more often, and [[eventually]], all of [[our
code]] is [[going]] to have [[::to(look)]] like this.
Received on 2026-02-10 23:36:59
