-
Notifications
You must be signed in to change notification settings - Fork 14.7k
[clang][Sema] Fix the continue and break scope for while loops #152606
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Make sure we don't push the break and continue scope for a while loop until after we have evaluated the condition.
@llvm/pr-subscribers-clang Author: Oliver Hunt (ojhunt) ChangesMake sure we don't push the break and continue scope for a while loop until after we have evaluated the condition. Full diff: https://github.com/llvm/llvm-project/pull/152606.diff 3 Files Affected:
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 0e9fcaa5fac6a..4062c4b7a6fdb 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -161,6 +161,8 @@ Bug Fixes in This Version
targets that treat ``_Float16``/``__fp16`` as native scalar types. Previously
the warning was silently lost because the operands differed only by an implicit
cast chain. (#GH149967).
+- Correct the continue and break scope for while statements to be after the
+ condition is evaluated.
Bug Fixes to Compiler Builtins
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp
index bf1978c22ee9f..b1b700951231f 100644
--- a/clang/lib/Parse/ParseStmt.cpp
+++ b/clang/lib/Parse/ParseStmt.cpp
@@ -1734,7 +1734,6 @@ StmtResult Parser::ParseWhileStatement(SourceLocation *TrailingElseLoc) {
Scope::DeclScope | Scope::ControlScope;
else
ScopeFlags = Scope::BreakScope | Scope::ContinueScope;
- ParseScope WhileScope(this, ScopeFlags);
// Parse the condition.
Sema::ConditionResult Cond;
@@ -1744,6 +1743,8 @@ StmtResult Parser::ParseWhileStatement(SourceLocation *TrailingElseLoc) {
Sema::ConditionKind::Boolean, LParen, RParen))
return StmtError();
+ ParseScope WhileScope(this, ScopeFlags);
+
// OpenACC Restricts a while-loop inside of certain construct/clause
// combinations, so diagnose that here in OpenACC mode.
SemaOpenACC::LoopInConstructRAII LCR{getActions().OpenACC()};
diff --git a/clang/test/Sema/while-loop-condition-scope.c b/clang/test/Sema/while-loop-condition-scope.c
new file mode 100644
index 0000000000000..d87362bdc668d
--- /dev/null
+++ b/clang/test/Sema/while-loop-condition-scope.c
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+void f() {
+ while (({ continue; 1; })) {
+ // expected-error@-1 {{'continue' statement not in loop statement}}
+
+ }
+ while (({ break; 1; })) {
+ // expected-error@-1 {{'break' statement not in loop or switch statement}}
+ }
+}
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The main thing I’m still not sure about since I noticed that we allow this is whether it’s a bug or a ‘feature’ (I could imagine some horrible macros maybe making use of this but there ought to be better alternatives...), because we also allow this for for
and do while
loops, and at least in the case of the former it’s quite intentional apparently: a875721
If it is intentional for the other loops too we should definitely document that though because it’s rather odd out of context...
CC @zygoloid: Also, the commit above cites GCC compatibility as a reason for allowing this in for
loops, but I can’t seem to find a GCC version on godbolt that actually accepts this or any of our test cases that that commit added. So unless I’m missing something, it doesn’t seem like GCC ever actually supported this?
It looks like GCC changed their behavior in version 9 onwards. In prior versions, a Prior to C++11, various major libraries (including both boost and Qt, as I recall) provided foreach macros that relied on this behavior, so Clang had to follow it. And instead of following it only in C++ and only when there's an enclosing loop, we chose to behave more consistently and allow it in both C and C++, regardless of whether there's an enclosing loop. It looks like GCC 9 onwards finally converged on the more sensible behavior -- that |
Ah, I didn’t think that having an outer loop mattered; that’s why I couldn’t get it to work. |
I’d say we should at least try to get rid of it; considering that GCC doesn’t support it either anymore it’s probably fine. @ojhunt It’d be nice to also remove support for this from |
Make sure we don't push the break and continue scope for a while loop until after we have evaluated the condition.