summaryrefslogtreecommitdiffstats
path: root/lib/Sema/Scope.cpp
diff options
context:
space:
mode:
authorSerge Pavlov <sepavloff@gmail.com>2013-10-21 09:34:44 +0000
committerSerge Pavlov <sepavloff@gmail.com>2013-10-21 09:34:44 +0000
commitfb90266d8bb5a977de45d07e702277f4cb54d74e (patch)
tree2b60de2155933f180adbfc19b625d2036bf453ff /lib/Sema/Scope.cpp
parentd186f0b4c15d4c63e0ae7fbe6ca3207871ba2eb9 (diff)
Fix to PR8880 (clang dies processing a for loop).
Due to statement expressions supported as GCC extension, it is possible to put 'break' or 'continue' into a loop/switch statement but outside its body, for example: for ( ; ({ if (first) { first = 0; continue; } 0; }); ) Such usage must be diagnosed as an error, GCC rejects it. To recognize this and similar patterns the flags BreakScope and ContinueScope are temporarily turned off while parsing condition expression. Differential Revision: http://llvm-reviews.chandlerc.com/D1762 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@193073 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/Scope.cpp')
-rw-r--r--lib/Sema/Scope.cpp37
1 files changed, 37 insertions, 0 deletions
diff --git a/lib/Sema/Scope.cpp b/lib/Sema/Scope.cpp
index 10f12ce844..8c2a8b3773 100644
--- a/lib/Sema/Scope.cpp
+++ b/lib/Sema/Scope.cpp
@@ -69,3 +69,40 @@ bool Scope::containedInPrototypeScope() const {
}
return false;
}
+
+void Scope::SetFlags(unsigned FlagsToSet) {
+ assert((FlagsToSet & ~(BreakScope | ContinueScope)) == 0 ||
+ "Unsupported scope flags");
+ assert ((Flags & ControlScope) != 0 || "Must be control scope");
+ if (FlagsToSet & BreakScope) {
+ assert((Flags & BreakScope) == 0 || "Already set");
+ BreakParent = this;
+ }
+ if (FlagsToSet & ContinueScope) {
+ assert((Flags & ContinueScope) == 0 || "Already set");
+ ContinueParent = this;
+ }
+ Flags |= FlagsToSet;
+}
+
+void Scope::ClearFlags(unsigned FlagsToClear) {
+ assert((FlagsToClear & ~(BreakScope | ContinueScope)) == 0 ||
+ "Unsupported scope flags");
+ if (FlagsToClear & BreakScope) {
+ assert((Flags & ControlScope) != 0 || "Must be control scope");
+ assert((Flags & BreakScope) != 0 || "Already cleared");
+ // This is a loop or switch scope. Flag BreakScope is removed temporarily
+ // when parsing the loop or switch header, to prevent constructs like this:
+ // \code
+ // while (({ if(a>N) break; a}))
+ // \endcode
+ BreakParent = 0;
+ }
+ if (FlagsToClear & ContinueScope) {
+ assert ((Flags & ControlScope) != 0 || "Must be control scope");
+ assert((Flags & ContinueScope) != 0 || "Already cleared");
+ ContinueParent = 0;
+ }
+ Flags &= ~FlagsToClear;
+}
+