Hi Aaron, On Mon, Jan 05, 2026 at 09:33:47AM -0500, Aaron Ballman wrote: > > > Attributes can be applied to statements, so I fail to see what the > > > issue is here? > > > > That was part of the ad-hoc fitting process I'm critizising. Before > > [[fallthrough]], no other attributes could attribute a statement, right? > > No *standard* attributes in C, yes. There are vendor attributes which > do (clang::musttail, etc) as well as C++ standard attributes which do > (likely, unlikely). Statement attributes have been a part of this > feature since day one.
Hmmm, the clang::musttail attribute makes sense. That one really does
attribute the statement. Thanks!
[...]
> > > > > > fallthrough is a jump statement misusing the syntax of an attribute.
> > > > >
> > > > > Incorrect. It is not a jump statement, it has no semantic effect. See
> > > > > 6.7.13.6
> > > >
> > > > It is not defined by the standard to be a jump statement, but we could
> > > > perfectly define it as such if we wanted. And it would fit much better
> > > > than "an attribute to the null statement" or "an attribute declaration".
> > >
> > > I don't agree; when we start making non-jumps into jumps, we
> > > complicate things for no benefit (for example, we then have to think
> > > about every place we put constraints on jumps and targets and decide
> > > what to do with these non-jumps).
> >
> > Could you give an example where this could go wrong?
>
> e.g., when discussing the defer TS, we decided that you cannot jump
> into or out of a defer block but can jump within one. So is this now
> jumping out of a defer block?
>
> defer {
> ;
> }
>
> Obviously, it's not jumping out of a defer block but it's the kind of
> thing we have start considering every time someone says "jump".
But nobody is talking about making ';' a jump statement. I'm taking
about explicit jump statements.
And of course you should constrain
defer {
[[fallthrough]];
}
Just like you should contrain the equivalent jump statement
defer {
fallthrough;
}
> > > > > > It should have been 'fallthrough;', with syntax similar to
> > > > > > 'continue;'
> > > > > > et al.. What it does is best described as "jump to the next
> > > > > > 'case'",
> > > > > > with a constraint that the statement must be the last statement at
> > > > > > the
> > > > > > top-level of a 'case'.
> > > > >
> > > > > No, it really does not. It's a hint to the compiler saying "the
> > > > > semantics of this code is intended". It's not a jump to the next case
> > > > > in the same way that a semi colon is not a jump to the next statement;
> > > > > it's following the flow of execution laid out by the abstract machine.
> > > >
> > > > It is a jump statement, just like a return statement at the end of a
> > > > function that return void is a jump statement, or a continue statement
> > > > at the end of a loop is a jump statement too.
> > >
> > > Jump statements emit branching instructions, fallthrough (and semi
> > > colons) do not.
> >
> > This isn't true. Here's a counter-example:
> >
> > #include <stdio.h>
> > int
> > main(int argc, char *[])
> > {
> > switch(argc) {
> > default:
> > puts("foo");
> > break;
> > }
> > puts("bar");
> > return 0;
> > }
> >
> > 'break' is a jump statement, and there's no branching instruction.
> >
> > That's because branching instructions are an implementation detail that
> > isn't inherent to the abstract machine.
> >
> > A jump statement is defined as
> > "A jump statement causes an unconditional jump to another place"
> >
> > And that's exactly what a jump statement does; no more, no less.
> >
> > Consider a hypothetical C dialect that decided to switch the default
> > behavior of switch so that if you don't say anything you'd break out of
> > the switch. Then, 'fallthrough' would --within the abstract machine--
> > be clearly a jump statement, as it unconditionally jumps to a place
> > where by default the code wouldn't go. The fact that when translating
> > to assembly you'll use branching instructions or not is irrelevant.
> >
> > Admittedly, that example would be unlikely, but you could consider
> > a more realistic C dialect that decided that a case without an explicit
> > fallthrough or break would be a constraint violation. That is, there
> > would be no natural behavior for a case, and it should always be
> > explicitly requested. This is actually implemented by both GCC (and
> > I suppose Clang too) as '-Wimplicit-fallthrough=5'.
> >
> > In the abstract machine corresponding to the '-Wimplicit-fallthrough=5'
> > dialect, fallthrough is clearly a jump statement, as it jumps to a place
> > that you'd otherwise not reach as part of the abstract machine.
You didn't reply to this; I'm interested in your response.
[...]
> > My proposal, as discussed with you, is to add a mandatory diagnostic
> > (contraint violation) about the presence of unrecognized attributes.
> > Nothing else.
>
> And that's what I'm opposed to. :-)
>
> >
> > This indeed matches the default behavior of both GCC and Clang, and
> > I expect to also match every other quality compiler.
> >
> > alx@devuan:~/tmp$ cat attr.c
> > [[attr]]
> > int
> > main(void)
> > {
> > return 0;
> > }
> > alx@devuan:~/tmp$ gcc attr.c
> > attr.c:1:1: warning: ‘attr’ attribute ignored [-Wattributes]
> > 1 | [[attr]]
> > | ^
> > alx@devuan:~/tmp$ clang attr.c
> > attr.c:1:3: warning: unknown attribute 'attr' ignored
> > [-Wunknown-attributes]
> > 1 | [[attr]]
> > | ^~~~
> > 1 warning generated.
> >
> > And in compilers that don't want to implement any attributes, it should
> > be trivial to emit a diagnostic saying "Attributes are not supported".
> >
> > Is that okay to you?
>
> No, for a few reasons.
>
> 1) Different vendors have different pressures and so just because
> Clang and GCC decided to diagnose this case does not mean everyone
> should be required to diagnose this case.
> 2) A constraint violation means something very different and I do not
> think you want us to go down the route you're taking us -- we've
> worked hard to change perception to be that a constraint violation is
> an error whenever possible and not just "emit any old diagnostic".
I certainly want to enforce the constraint. If it were by me, you could
make it a hard error.
> e.g., the standard is telling you that your code is wrong. Not "I wish
> you'd write it another way", but "this should not translate into
> semantics for the abstract machine" kind of wrong.
Well, if you're writing code for a compiler that doesn't want to support
attributes at all, using attributes is indeed wrong, isn't it?
> If you don't want
> these to be errors, constraint violation is the wrong tool for the job
> and recommended practice is a better way to go.
> 3) Attributes are useful for forward compatibility and diagnosing
> unknown ones can be an annoyance to users in practice. Currently, the
> only tools users have to control those diagnostics is to turn off
> diagnostics for *all* unknown attributes. Clang tried designing a -W
> flag that would work well to let you selectively disable diagnostics;
> the idea died on the vine because it's actually challenging to design
> a usable command line flag for that when you consider `-Wno-` variants
> so we don't even have tools in the compiler to make your suggestion
> less frustrating in practice.
I'm interested in this. What was the problem? Is it possible to do
-Wno-attributes=foo to disable [[foo]] and ...=gnu::bar to disable
[[gnu::bar]]?
Have a lovely night!
Alex
>
> ~Aaron
>
> >
> > > WG21 added an attribute that was not a hint to the compiler and it has
> > > been a mess that implementations are still dealing with five+ years
> > > later; I do not support following down the same path for C.
> > >
> > > ~Aaron
> >
> > Have a lovely New Year!
> > Alex
> >
> > --
> > <https://www.alejandro-colomar.es>
--
<https://www.alejandro-colomar.es>
signature.asc
Description: PGP signature
