Make Scope keep track of the kind of scope it is. Properly scope loop and
switch statements. Make break/continue check that they are inside of an
appropriate control-flow construct. This implements Parser/bad-control.c.
llvm-svn: 39136
diff --git a/clang/Parse/ParseStmt.cpp b/clang/Parse/ParseStmt.cpp
index f005008..4c56853 100644
--- a/clang/Parse/ParseStmt.cpp
+++ b/clang/Parse/ParseStmt.cpp
@@ -15,6 +15,7 @@
#include "clang/Parse/Parser.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Parse/SemaDecl.h"
+#include "clang/Parse/Scope.h"
using namespace llvm;
using namespace clang;
@@ -136,13 +137,11 @@
SemiError = "goto statement";
break;
case tok::kw_continue: // C99 6.8.6.2: continue-statement
- Res = Actions.ParseContinueStmt(Tok.getLocation());
- ConsumeToken(); // eat the 'continue'.
+ Res = ParseContinueStatement();
SemiError = "continue statement";
break;
case tok::kw_break: // C99 6.8.6.3: break-statement
- Res = Actions.ParseBreakStmt(Tok.getLocation());
- ConsumeToken(); // eat the 'break'.
+ Res = ParseBreakStatement();
SemiError = "break statement";
break;
case tok::kw_return: // C99 6.8.6.4: return-statement
@@ -368,7 +367,7 @@
SourceLocation LBraceLoc = ConsumeBrace(); // eat the '{'.
// Enter a scope to hold everything within the compound stmt.
- EnterScope();
+ EnterScope(0);
SmallVector<StmtTy*, 32> Stmts;
while (Tok.getKind() != tok::r_brace && Tok.getKind() != tok::eof) {
@@ -443,11 +442,16 @@
return true;
}
+ // Start the switch scope.
+ EnterScope(Scope::BreakScope);
+
// Parse the condition.
ExprResult Cond = ParseSimpleParenExpression();
// Read the body statement.
StmtResult Body = ParseStatement();
+
+ ExitScope();
if (Cond.isInvalid || Body.isInvalid) return true;
@@ -468,11 +472,16 @@
return true;
}
+ // Start the loop scope.
+ EnterScope(Scope::BreakScope | Scope::ContinueScope);
+
// Parse the condition.
ExprResult Cond = ParseSimpleParenExpression();
// Read the body statement.
StmtResult Body = ParseStatement();
+
+ ExitScope();
if (Cond.isInvalid || Body.isInvalid) return true;
@@ -487,10 +496,14 @@
assert(Tok.getKind() == tok::kw_do && "Not a do stmt!");
SourceLocation DoLoc = ConsumeToken(); // eat the 'do'.
+ // Start the loop scope.
+ EnterScope(Scope::BreakScope | Scope::ContinueScope);
+
// Read the body statement.
StmtResult Body = ParseStatement();
if (Tok.getKind() != tok::kw_while) {
+ ExitScope();
Diag(Tok, diag::err_expected_while);
Diag(DoLoc, diag::err_matching, "do");
SkipUntil(tok::semi);
@@ -499,6 +512,7 @@
SourceLocation WhileLoc = ConsumeToken();
if (Tok.getKind() != tok::l_paren) {
+ ExitScope();
Diag(Tok, diag::err_expected_lparen_after, "do/while");
SkipUntil(tok::semi);
return true;
@@ -506,6 +520,9 @@
// Parse the condition.
ExprResult Cond = ParseSimpleParenExpression();
+
+ ExitScope();
+
if (Cond.isInvalid || Body.isInvalid) return true;
return Actions.ParseDoStmt(DoLoc, Body.Val, WhileLoc, Cond.Val);
@@ -524,6 +541,8 @@
SkipUntil(tok::semi);
return true;
}
+
+ EnterScope(Scope::BreakScope | Scope::ContinueScope);
SourceLocation LParenLoc = ConsumeParen();
ExprResult Value;
@@ -540,7 +559,7 @@
if (!getLang().C99) // Use of C99-style for loops in C90 mode?
Diag(Tok, diag::ext_c99_variable_decl_in_for_loop);
ParseDeclaration(Declarator::ForContext);
- // FIXME: Turn declaration into stmt.
+ // FIXME: Turn declaration into a stmt ast node.
FirstPart = 0;
} else {
Value = ParseExpression();
@@ -592,6 +611,10 @@
// Read the body statement.
StmtResult Body = ParseStatement();
+
+ // Leave the for-scope.
+ ExitScope();
+
if (Body.isInvalid)
return Body;
@@ -629,6 +652,45 @@
return Res;
}
+/// ParseContinueStatement
+/// jump-statement:
+/// 'continue' ';'
+///
+/// Note: this lets the caller parse the end ';'.
+///
+Parser::StmtResult Parser::ParseContinueStatement() {
+ SourceLocation ContinueLoc = ConsumeToken(); // eat the 'continue'.
+
+ Scope *S = CurScope->getContinueParent();
+ if (!S) {
+ Diag(ContinueLoc, diag::err_continue_not_in_loop);
+ return true;
+ }
+
+ // FIXME: Remember that this continue goes with this loop.
+
+ return Actions.ParseContinueStmt(ContinueLoc);
+}
+
+/// ParseBreakStatement
+/// jump-statement:
+/// 'break' ';'
+///
+/// Note: this lets the caller parse the end ';'.
+///
+Parser::StmtResult Parser::ParseBreakStatement() {
+ SourceLocation BreakLoc = ConsumeToken(); // eat the 'break'.
+
+ Scope *S = CurScope->getBreakParent();
+ if (!S) {
+ Diag(BreakLoc, diag::err_break_not_in_loop_or_switch);
+ return true;
+ }
+
+ // FIXME: Remember that this break goes with this loop/switch.
+ return Actions.ParseBreakStmt(BreakLoc);
+}
+
/// ParseReturnStatement
/// jump-statement:
/// 'return' expression[opt] ';'