diff options
author | Serge Pavlov <sepavloff@gmail.com> | 2013-10-21 09:34:44 +0000 |
---|---|---|
committer | Serge Pavlov <sepavloff@gmail.com> | 2013-10-21 09:34:44 +0000 |
commit | 6652921d5aba1e5c158212d288d2b7d6e53386c8 (patch) | |
tree | fb23cb362c0e8c0fb7df46afa05ff11d9510a5e3 /clang/lib/Sema/Scope.cpp | |
parent | b773785a593592020a449dfcfe65bd4e4f93fe71 (diff) | |
download | bcm5719-llvm-6652921d5aba1e5c158212d288d2b7d6e53386c8.tar.gz bcm5719-llvm-6652921d5aba1e5c158212d288d2b7d6e53386c8.zip |
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
llvm-svn: 193073
Diffstat (limited to 'clang/lib/Sema/Scope.cpp')
-rw-r--r-- | clang/lib/Sema/Scope.cpp | 37 |
1 files changed, 37 insertions, 0 deletions
diff --git a/clang/lib/Sema/Scope.cpp b/clang/lib/Sema/Scope.cpp index 10f12ce844f..8c2a8b37735 100644 --- a/clang/lib/Sema/Scope.cpp +++ b/clang/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; +} + |