tl;dr: This makes e.g. `while (({ break; 1; })) {}` ill-formed.
GCC used to allow this a long time ago (< GCC 9 I believe), but
eventually removed support for it; we originally allowed this both for
GCC compatibility and because there was actual code in the wild using it
(see Richard’s comment here for more background:
https://github.com/llvm/llvm-project/pull/152606#issuecomment-3166130973).
Note that this _is_ still allowed inside another loop, e.g. this
```c++
for (;;) {
while (({ break; true; })) {}
}
```
is well-formed; the `break` here will break out of the `for` loop.
Removing support for this gets rid of quite a bit of code and has a few
more benefits:
1. Currently, GCC and Clang _disagree_ on the meaning of this construct
in nested loops: in the code snippet above, Clang breaks out of the
`while` loop, whereas GCC breaks out of the `for` loop; this patch
changes Clang to align with GCC here. As a result, we can also remove
code that emits a warning for such cases.
2. It frees up a bit in `ScopeFlags::Flags`, which is a good thing
because I need one for expansion statements, and we’re out of bits. This
is because we currently use a bit as a hack to disallow `continue`
inside the declaration of the condition variable (because we’d
`continue` to the condition before initialising the variable); this bit
becomes obsolete with this patch because `continue` is now disallowed
entirely within the condition (if there is no outer loop).
Without this change, I’d have to refactor `Flags` to be a 64-bit
integer, which would also entail updating every place where we use an
`unsigned` to store scope flags.
There is another change that I needed to make here: we currently
suppress `-Wcomma` (which warns about comma operators, because in most
contexts, you probably didn’t mean to use one) in some places, including
the third part of a C-style `for` loop. This is implemented by checking
if we’re in a `BreakScope | ContinueScope`, but those scope flags are
now only set when parsing the loop body. Instead, we now check for
`ControlScope`. This requires us to also set that flag in C90 mode, but
that seems to be harmless as the only use of `ControlScope` I was able
to find is in C++ code paths, where that bit was already set anyway.
When we introduced named loops for C2y, we purposefully didn’t support
labeled break/continue in the condition, so there’s nothing to be done
there (we already have tests for this too).