[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