[cfe-commits] r39136 - in /cfe/cfe/trunk: Parse/ParseStmt.cpp Parse/Parser.cpp clang.xcodeproj/project.pbxproj include/clang/Basic/DiagnosticKinds.def include/clang/Parse/Parser.h include/clang/Parse/Scope.h test/Parser/bad-control.c
sabre at cs.uiuc.edu
sabre at cs.uiuc.edu
Wed Jul 11 09:27:55 PDT 2007
Author: sabre
Date: Wed Jul 11 11:27:55 2007
New Revision: 39136
URL: http://llvm.org/viewvc/llvm-project?rev=39136&view=rev
Log:
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.
Added:
cfe/cfe/trunk/test/Parser/bad-control.c (with props)
Modified:
cfe/cfe/trunk/Parse/ParseStmt.cpp
cfe/cfe/trunk/Parse/Parser.cpp
cfe/cfe/trunk/clang.xcodeproj/project.pbxproj
cfe/cfe/trunk/include/clang/Basic/DiagnosticKinds.def
cfe/cfe/trunk/include/clang/Parse/Parser.h
cfe/cfe/trunk/include/clang/Parse/Scope.h
Modified: cfe/cfe/trunk/Parse/ParseStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/Parse/ParseStmt.cpp?rev=39136&r1=39135&r2=39136&view=diff
==============================================================================
--- cfe/cfe/trunk/Parse/ParseStmt.cpp (original)
+++ cfe/cfe/trunk/Parse/ParseStmt.cpp Wed Jul 11 11:27:55 2007
@@ -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] ';'
Modified: cfe/cfe/trunk/Parse/Parser.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/Parse/Parser.cpp?rev=39136&r1=39135&r2=39136&view=diff
==============================================================================
--- cfe/cfe/trunk/Parse/Parser.cpp (original)
+++ cfe/cfe/trunk/Parse/Parser.cpp Wed Jul 11 11:27:55 2007
@@ -187,8 +187,8 @@
//===----------------------------------------------------------------------===//
/// EnterScope - Start a new scope.
-void Parser::EnterScope() {
- CurScope = new Scope(CurScope);
+void Parser::EnterScope(unsigned ScopeFlags) {
+ CurScope = new Scope(CurScope, ScopeFlags);
}
/// ExitScope - Pop a scope off the scope stack.
@@ -218,7 +218,7 @@
// Create the global scope, install it as the current scope.
assert(CurScope == 0 && "A scope is already active?");
- EnterScope();
+ EnterScope(0);
// Install builtin types.
@@ -393,7 +393,7 @@
"This isn't a function declarator!");
// FIXME: Enter a scope for the arguments.
- //EnterScope();
+ //EnterScope(Scope::FnScope);
Modified: cfe/cfe/trunk/clang.xcodeproj/project.pbxproj
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/clang.xcodeproj/project.pbxproj?rev=39136&r1=39135&r2=39136&view=diff
==============================================================================
--- cfe/cfe/trunk/clang.xcodeproj/project.pbxproj (original)
+++ cfe/cfe/trunk/clang.xcodeproj/project.pbxproj Wed Jul 11 11:27:55 2007
@@ -127,7 +127,7 @@
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
- 8DD76F6C0486A84900D96B5E /* clang */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = "compiled.mach-o.executable"; path = clang; sourceTree = BUILT_PRODUCTS_DIR; };
+ 8DD76F6C0486A84900D96B5E /* clang */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = clang; sourceTree = BUILT_PRODUCTS_DIR; };
DE06B73D0A8307640050E87E /* LangOptions.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = LangOptions.h; sourceTree = "<group>"; };
DE06BECA0A854E4B0050E87E /* Scope.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = Scope.h; path = clang/Parse/Scope.h; sourceTree = "<group>"; };
DE06D42F0A8BB52D0050E87E /* Parser.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = Parser.cpp; path = Parse/Parser.cpp; sourceTree = "<group>"; };
Modified: cfe/cfe/trunk/include/clang/Basic/DiagnosticKinds.def
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/include/clang/Basic/DiagnosticKinds.def?rev=39136&r1=39135&r2=39136&view=diff
==============================================================================
--- cfe/cfe/trunk/include/clang/Basic/DiagnosticKinds.def (original)
+++ cfe/cfe/trunk/include/clang/Basic/DiagnosticKinds.def Wed Jul 11 11:27:55 2007
@@ -389,4 +389,9 @@
DIAG(err_unspecified_vla_size_with_static, ERROR,
"'static' may not be used with an unspecified variable length array size")
+DIAG(err_continue_not_in_loop, ERROR,
+ "'continue' statement not in loop statement")
+DIAG(err_break_not_in_loop_or_switch, ERROR,
+ "'break' statement not in loop or switch statement")
+
#undef DIAG
Modified: cfe/cfe/trunk/include/clang/Parse/Parser.h
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/include/clang/Parse/Parser.h?rev=39136&r1=39135&r2=39136&view=diff
==============================================================================
--- cfe/cfe/trunk/include/clang/Parse/Parser.h (original)
+++ cfe/cfe/trunk/include/clang/Parse/Parser.h Wed Jul 11 11:27:55 2007
@@ -212,7 +212,7 @@
// Scope manipulation
/// EnterScope - Start a new scope.
- void EnterScope();
+ void EnterScope(unsigned ScopeFlags);
/// ExitScope - Pop a scope off the scope stack.
void ExitScope();
@@ -317,6 +317,8 @@
StmtResult ParseDoStatement();
StmtResult ParseForStatement();
StmtResult ParseGotoStatement();
+ StmtResult ParseContinueStatement();
+ StmtResult ParseBreakStatement();
StmtResult ParseReturnStatement();
StmtResult ParseAsmStatement();
void ParseAsmOperandsOpt();
Modified: cfe/cfe/trunk/include/clang/Parse/Scope.h
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/include/clang/Parse/Scope.h?rev=39136&r1=39135&r2=39136&view=diff
==============================================================================
--- cfe/cfe/trunk/include/clang/Parse/Scope.h (original)
+++ cfe/cfe/trunk/include/clang/Parse/Scope.h Wed Jul 11 11:27:55 2007
@@ -19,19 +19,58 @@
namespace llvm {
namespace clang {
-
+
+
/// Scope - A scope is a transient data structure that is used while parsing the
/// program. It assists with resolving identifiers to the appropriate
/// declaration.
///
class Scope {
+public:
+ /// ScopeFlags - These are bitfields that are or'd together when creating a
+ /// scope, which defines the sorts of things the scope contains.
+ enum ScopeFlags {
+ /// FnScope - This indicates that the scope corresponds to a function, which
+ /// means that labels are set here.
+ FnScope = 0x01,
+
+ /// BreakScope - This is a while,do,switch,for, etc that can have break
+ /// stmts embedded into it.
+ BreakScope = 0x02,
+
+ /// ContinueScope - This is a while,do,for, which can have continue
+ /// stmt embedded into it.
+ ContinueScope = 0x04,
+
+ /// HasBreak - This flag is set on 'BreakScope' scopes, when they actually
+ /// do contain a break stmt.
+ HasBreak = 0x08,
+
+ /// HasContinue - This flag is set on 'ContinueScope' scopes, when they
+ /// actually do contain a continue stmt.
+ HasContinue = 0x10
+ };
+private:
/// The parent scope for this scope. This is null for the translation-unit
/// scope.
- Scope *Parent;
+ Scope *AnyParent;
/// Depth - This is the depth of this scope. The translation-unit scope has
/// depth 0.
- unsigned Depth;
+ unsigned Depth : 16;
+
+ /// Flags - This contains a set of ScopeFlags, which indicates how the scope
+ /// interrelates with other control flow statements.
+ unsigned Flags : 8;
+
+ /// FnParent - If this scope has a parent scope that is a function body, this
+ /// pointer is non-null and points to it. This is used for label processing.
+ Scope *FnParent;
+
+ /// BreakParent/ContinueParent - This is a direct link to the immediately
+ /// preceeding BreakParent/ContinueParent if this scope is not one, or null if
+ /// there is no containing break/continue scope.
+ Scope *BreakParent, *ContinueParent;
/// DeclsInScope - This keeps track of all declarations in this scope. When
/// the declaration is added to the scope, it is set as the current
@@ -41,12 +80,42 @@
/// implement these semantics.
SmallVector<Action::DeclTy*, 32> DeclsInScope;
public:
- Scope(Scope *parent) : Parent(parent), Depth(Parent ? Parent->Depth+1 : 0) {
+ Scope(Scope *parent, unsigned ScopeFlags)
+ : AnyParent(parent), Depth(AnyParent ? AnyParent->Depth+1 : 0),
+ Flags(ScopeFlags){
+ assert((Flags & (HasBreak|HasContinue)) == 0 &&
+ "These flags can't be set in ctor!");
+
+ if (AnyParent) {
+ FnParent = AnyParent->FnParent;
+ BreakParent = AnyParent->BreakParent;
+ ContinueParent = AnyParent->ContinueParent;
+ } else {
+ FnParent = BreakParent = ContinueParent = 0;
+ }
+
+ // If this scope is a function or contains breaks/continues, remember it.
+ if (Flags & FnScope) FnParent = this;
+ if (Flags & BreakScope) BreakParent = this;
+ if (Flags & ContinueScope) ContinueParent = this;
}
/// getParent - Return the scope that this is nested in.
///
- Scope *getParent() const { return Parent; }
+ Scope *getParent() const { return AnyParent; }
+
+ /// getContinueParent - Return the closest scope that a continue statement
+ /// would be affected by.
+ Scope *getContinueParent() const {
+ return ContinueParent;
+ }
+
+ /// getBreakParent - Return the closest scope that a break statement
+ /// would be affected by.
+ Scope *getBreakParent() const {
+ return BreakParent;
+ }
+
typedef SmallVector<Action::DeclTy*, 32>::iterator decl_iterator;
typedef SmallVector<Action::DeclTy*, 32>::const_iterator decl_const_iterator;
Added: cfe/cfe/trunk/test/Parser/bad-control.c
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/test/Parser/bad-control.c?rev=39136&view=auto
==============================================================================
--- cfe/cfe/trunk/test/Parser/bad-control.c (added)
+++ cfe/cfe/trunk/test/Parser/bad-control.c Wed Jul 11 11:27:55 2007
@@ -0,0 +1,9 @@
+/* RUN: clang -parse-noop %s 2>&1 | grep error: | wc -l | grep 2
+*/
+int foo() {
+break;
+}
+
+int foo2() {
+continue;
+}
Propchange: cfe/cfe/trunk/test/Parser/bad-control.c
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cfe/cfe/trunk/test/Parser/bad-control.c
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
More information about the cfe-commits
mailing list